2011-12-09 31 views
5

này tốt nhất có thể được minh họa bằng ví dụ (tất cả các ví dụ giả ast được nhập khẩu; lưu ý rằng tôi đang sử dụng Python 2.7.1):Tại sao Python chèn Không vào các bước cắt?

# Outputs: Slice(lower=Num(n=1), upper=Num(n=10), step=None) 
ast.dump(ast.parse("l[1:10]").body[0].value.slice) 

# Outputs: Slice(lower=Num(n=1), upper=Num(n=10), step=Name(id='None', ctx=Load())) 
ast.dump(ast.parse("l[1:10:]").body[0].value.slice) 

# Outputs: Slice(lower=Num(n=1), upper=None, step=None) 
ast.dump(ast.parse("l[1:]").body[0].value.slice) 

# Outputs: Slice(lower=None, upper=None, step=None) 
ast.dump(ast.parse("l[:]").body[0].value.slice) 

Vì vậy, như chúng ta có thể thấy, l[1:10] kết quả trong một nút AST có lát có hai con - lowerupper cả hai được đặt thành chữ số - và con thứ ba trống là số step. Nhưng [1:10:], mà chúng ta sẽ nghĩ là giống hệt nhau, đặt con của nó là step của slice là biểu thức nghĩa đen().

Được rồi, tôi nghĩ vậy. Có thể Python xử lý l[1:10:]l[1:10] là các loại biểu thức hoàn toàn khác nhau. Tham chiếu biểu thức Python (link) chắc chắn dường như chỉ ra như vậy; l[1:10] là một lát cắt đơn giản, nhưng l[1:10:] là một lát cắt mở rộng (chỉ với một lát cắt).

Nhưng, ngay cả trong bối cảnh cắt lát mở rộng, đối số bước được xử lý đặc biệt. Nếu chúng ta cố gắng phớt lờ phía trên hoặc thấp hơn bị ràng buộc trong một lát mở rộng với một mục lát, chúng tôi chỉ kết thúc với con trống:

# Outputs: Slice(lower=Num(n=1), upper=None, step=Name(id='None', ctx=Load())) 
ast.dump(ast.parse("l[1::]").body[0].value.slice) 

# Outputs: Slice(lower=None, upper=Num(n=10), step=Name(id='None', ctx=Load())) 
ast.dump(ast.parse("l[:10:]").body[0].value.slice) 

Hơn nữa, sau khi kiểm tra hơn nữa AST không thậm chí đối xử với những slicings như slicings mở rộng . Đây là những gì mở rộng slicings thực sự trông giống như:

# Outputs: ExtSlice(dims=[Slice(lower=None, upper=None, step=Name(id='None', ctx=Load())), Slice(lower=None, upper=None, step=Name(id='None', ctx=Load()))]) 
ast.dump(ast.parse("l[::, ::]").body[0].value.slice) 

Vì vậy, đây là kết luận của tôi: AST luôn đối xử với các step tham số đặc biệt đối với một số lý do, và unrelatedly, nút Slice AST đại diện cho một lát dài (tôi đoán vậy có don không phải là hai lớp cơ sở khác nhau SliceShortSliceLongSlice - mặc dù tôi nghĩ rằng nó sẽ được ưa thích hơn) và do đó, một lát mở rộng một mục có thể được biểu diễn dưới dạng nút bình thường Slice và được thực hiện như vậy vì một số lý do. Nó chỉ có vẻ sai với tôi để cho phép các thông số None được hiểu là mặc định, nhưng tôi hiểu rằng đó là một quyết định thiết kế có mục đích; việc chèn None bằng chữ và xử lý các lát dài như các nút Slice dường như giống như tai nạn (hoặc các hiện vật thiết kế cũ).

Có ai khác có giải thích thông tin hơn không?

Trả lời

3

Nếu không điều trị như vậy trong ký hiệu lát mở rộng bạn sẽ không thể phân biệt giữa l[1:]l[1::], và bạn không thể gọi các phương pháp đặc biệt khác nhau - __getslice__ có thể được gọi cho một lát bình thường, nhưng __getitem__ phải được viện dẫn cho một lát mở rộng.

Vì vậy, nó chủ yếu là một điều tương thích ngược cho Python 2.x, mà đã biến mất trong Python 3.x:

Python 3.2 (r32:88445, Mar 25 2011, 19:28:28) 
[GCC 4.5.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import ast 
>>> ast.dump(ast.parse("l[1:]").body[0].value.slice) 
'Slice(lower=Num(n=1), upper=None, step=None)' 
>>> ast.dump(ast.parse("l[1::]").body[0].value.slice) 
'Slice(lower=Num(n=1), upper=None, step=None)' 
>>> 

Xem python2.7 source for ast.cdata model description để biết thêm.

Các vấn đề liên quan