2016-07-12 16 views
10

Trong đoạn mã sau, các mc assigment hoạt động tốt bằng Python 2 và 3.Quy tắc phạm vi hiểu danh sách trong lớp Python là gì?

Các cc chuyển nhượng, trong đó sử dụng danh sách hiểu giống nhau trong một lớp học, làm việc trong Python 2 nhưng không thành công với Python 3.

Điều gì giải thích hành vi này?

ml1 = "a b c".split() 
ml2 = "1 2 3".split() 
mc = [ i1 + i2 for i1 in ml1 for i2 in ml2 ] 

class Foo(object): 
    cl1 = ml1 
    cl2 = ml2 

    cc1 = [ i1 for i1 in cl1 ] 
    cc2 = [ i2 for i2 in cl2 ] 
    cc = [ i1 + i2 for i1 in cl1 for i2 in cl2 ] 


print("mc = ", mc) 
foo = Foo() 
print("cc = ", foo.cc) 

tôi có được điều này:

(default-3.5) snafu$ python2 /tmp/z.py 
('mc = ', ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']) 
('cc = ', ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']) 

(default-3.5) snafu$ python3 /tmp/z.py 
Traceback (most recent call last): 
    File "/tmp/z.py", line 5, in <module> 
    class Foo(object): 
    File "/tmp/z.py", line 11, in Foo 
    cc = [ i1 + i2 for i1 in cl1 for i2 in cl2 ] 
    File "/tmp/z.py", line 11, in <listcomp> 
    cc = [ i1 + i2 for i1 in cl1 for i2 in cl2 ] 
NameError: name 'cl2' is not defined 

Tại sao lớp biến cl2 không được định nghĩa? Lưu ý rằng nhiệm vụ cc2 hoạt động tốt, cũng như cc1. Trao đổi cl1cl2 trong sự hiểu biết cho thấy rằng vòng lặp thứ hai là một trong đó gây nên các ngoại lệ, không cl2 per se)

phiên bản:.

(default-3.5) snafu$ python2 --version 
Python 2.7.11+ 
(default-3.5) snafu$ python3 --version 
Python 3.5.1+ 
+0

Điều này liên quan đến biến lớp so với biến mẫu, không phải phạm vi hiểu. – TigerhawkT3

+0

@ TigerhawkT3: Trên thực tế, nó thực sự là về phạm vi biến ở mức độ hiểu lớp. – user2357112

+2

http://stackoverflow.com/questions/20136955/python3-nested-list-comprehension-scope –

Trả lời

2

Trong Python 3, danh sách comprehensions có phạm vi riêng của họ, tuân theo các quy tắc tương tự như phạm vi chức năng. Bạn biết các phương thức của một lớp không tự động nhìn vào bên trong phạm vi lớp để tìm kiếm biến không?

class Example: 
    var = 1 
    def this_fails(self): 
     print(var) 
Example().this_fails() # NameError 

cũng áp dụng đối với bất kỳ phạm vi chức năng lồng vào bên trong một phạm vi lớp học, bao gồm phạm vi hiểu danh sách. Việc tra cứu cl2 bên trong danh sách hiểu bỏ qua phạm vi lớp và đi thẳng đến các hình cầu. Nó có hiệu quả các công trình như thế này:

class Foo(object): 
    ... 
    def make_cc(outer_iterable): 
     result = [] 
     for i1 in outer_iterable: 
      for i2 in cl2: # This fails 
       result.append(i1 + i2) 
     return result 
    cc = make_cc(cl1) # cl1 is evaluated outside the comprehension scope, for reasons 

Lưu ý rằng việc tra cứu cl1 hoạt động tốt, bởi vì điều đó xảy ra ở phạm vi lớp học, ngoài sự hiểu biết, dù đã được cú pháp lồng vào bên trong sự hiểu biết. They made that decision trở lại khi Python giới thiệu genexps, bởi vì nó bắt một vài lỗi genexp phổ biến trước đó. Đó cũng là lý do tại sao hoạt động của tính năng đọc danh sách cc1cc2; việc sử dụng duy nhất các biến cấp lớp của chúng là ở bên ngoài (chỉ) for có thể lặp lại của chúng.

Sử dụng hiểu và biểu thức trình tạo bên trong tuyên bố lớp học là một mớ hỗn độn. Nó không nên, nhưng nó được. Dính vào các vòng lặp thông thường, hoặc chạy các sự hiểu biết bên ngoài câu lệnh của lớp để các ngữ nghĩa rõ ràng hơn.

+1

Điều này nghe có vẻ hợp lý, tuy nhiên, nó không giải thích (với tôi) tại sao 'cc1 = [i1 cho i1 trong cl1]' hoạt động nhưng 'cc = [i1 + i2 cho i1 trong cl1 cho i2 trong cl2]' không. Các quy tắc phạm vi sẽ không giống nhau? – mhawke

+0

@mhawke: Việc lặp lại 'for' đầu tiên được đánh giá bên ngoài phạm vi hiểu và được chuyển tới hàm ẩn danh làm đối số, rất có thể đối xứng với biểu thức trình tạo, hoạt động theo cách đó vì nó bắt gặp một số lỗi phổ biến trước đó. – user2357112

+0

"Sử dụng hiểu và biểu thức máy phát điện bên trong một tuyên bố lớp học là một mớ hỗn độn." Tôi đồng ý: Các bài tập 'cc1' và' cc2' thành công và việc phân bổ 'cc' thất bại dường như không đáng kể và không trực quan. – Reece

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