2012-12-26 25 views
5

Trong một ứng dụng appengine, tôi muốn xây dựng một tập hợp tất cả các tên thuộc tính cho một danh sách các đối tượng. này nên khá đơn giản:Sử dụng biểu thức trình tạo lồng nhau trong Python 2.7

users = security.User.all().fetch(1000) 
props = set([k for k in u.properties().keys() for u in users]) 

Tuy nhiên, các mã trên kết quả trong một lỗi:

File "/Users/paulkorzhyk/Projects/appengine-flask-template/app/app.py", line 70, in allusers 
props = set([k for k in u.properties().keys() for u in users]) 
UnboundLocalError: local variable 'u' referenced before assignment 

Sau khi một số thí nghiệm trong trình gỡ lỗi tôi đã nhận thấy rằng việc thêm một biểu hiện giả sửa mã:

users = security.User.all().fetch(1000) 
[u.properties().keys() for u in users] 
props = set([k for k in u.properties().keys() for u in users]) 

Điều này khá trực quan đối với tôi, tại sao phiên bản gốc thất bại trong Python 2.7? và tại sao thêm một biểu thức 'vô ích' ở giữa khắc phục vấn đề?

+0

Theo câu trả lời này http://stackoverflow.com/questions/8049798/understanding-nested-list-comprehension liên kết phải được trái sang phải và do đó sắp xếp lại các câu lệnh vòng lặp nên sửa chữa. – Ifthikhan

Trả lời

7

Chỉ cần thay đổi thứ tự đánh giá

props = set([k for k in u.properties().keys() for u in users]) 

để

props = set([k for u in users for k in u.properties().keys() ]) 

cũng có thể bạn không cần phải có sự hiểu biết danh sách nhưng biểu hiện máy phát điện với một sự hiểu biết bộ sẽ làm việc ở đây

props = set(k for u in users for k in u.properties().keys()) 

Thứ tự đánh giá từ phải sang trái

Trong biểu hiện ban đầu của bạn

set([k for k in u.properties().keys() for u in users]) 

có thể được chia như

for k in u.properties().keys(): # Here u is undefined 
    for u in users: 
     #what ever 

Các hiện tượng thú vị của việc sử dụng một biểu thức Dummy là một thực tế rằng Danh sách Hiểu Xì biến, gây u được tiết lộ trong phạm vi toàn cầu

Vì vậy,

[u.properties().keys() for u in users] 

rò rỉ u trong phạm vi toàn cầu,

mà làm

set([k for k in u.properties().keys() for u in users]) 

hợp pháp

Ví dụ sau đây cho thấy, làm thế nào danh sách hiểu rò rỉ biến

>>> del i 
>>> foo = [range(1,10) for _ in range(10)] 
>>> globals()['i'] 

Traceback (most recent call last): 
    File "<pyshell#84>", line 1, in <module> 
    globals()['i'] 
KeyError: 'i' 
>>> [i for i in foo] 
[[1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9]] 
>>> globals()['i'] 
[1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>> 
+0

Cảm ơn lời giải thích, thực sự hữu ích. Đây có phải là sự rò rỉ của các biến không? – Paul

+0

Đây không phải là lỗi mà là bài đăng Đặc trưng Python 2.3. Tính năng này đã bị xóa khỏi Python 3.0. Tham khảo http://docs.python.org/2/reference/expressions.html#id20 – Abhijit

1

Lý do ví dụ ban đầu của bạn bị lỗi là bạn có các mệnh đề for trong orde sai r. Các mệnh đề for trong danh sách/máy phát hiểu được theo thứ tự như chúng sẽ là nếu bạn đã viết mã ra như lồng nhau cho các vòng lặp. Đó là, cái ngoài cùng bên trái là ngoài cùng bên trái, cực bên phải là bên trong cùng bên trái. Chuyển đổi thứ tự của các mệnh đề for để làm cho nó hoạt động.

Lý do biểu thức giả thay đổi hành vi là biểu thức giả là danh sách hiểu và trong Python 2, việc hiểu danh sách (không giống như phát hiện máy phát) đã làm rò rỉ biến vòng lặp của chúng đến phạm vi bao quanh.Các rò rỉ u cho phép ví dụ thứ hai của bạn để chạy, nhưng nó không phải là làm những gì bạn nghĩ rằng đó là, vì các mệnh đề for của bạn trong dòng props = ... vẫn còn sai trật tự. Nó chỉ lặp qua một giá trị của u, cụ thể là giá trị u cuối cùng từ biểu thức giả.

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