2017-09-14 28 views
7

trong mã này:Tại sao các tên biến khác nhau lại có kết quả khác nhau (python2.7)?

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y): 
     return i 
    results.append(inner) 

for i in results: 
    print i(None) 

đầu ra là "chức năng nội tại 0x107dea668"

nếu tôi thay đổi i lá thư khác, ví dụ:

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y): 
     return i 
    results.append(inner) 

for j in results: 
    print j(None) 

đầu ra là "4"


trả lời

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y): 
     print "in inner:%s " % id(i) 
     return i 
    results.append(inner) 

# i -> 4 
for i in results: 
    # i -> func inner 
    print "i: %s" % i 
    print "in loop: %s " % id(i) 

    # func inner <===> A 
    # i == A -> return i -> return A, so when call funtion inner, will return itself 
    # print "call: %s" % i(None) 

    print "call: %s" % i(None)(None)(None) 
    print "------------------------------" 

i: chức năng nội tại 0x101344d70
trong vòng lặp: 4315172208
trong nội: 4315172208
trong nội: 4315172208
trong nội: 4315172208
gọi: hàm bên trong tại 0x101344d70

i: chức năng nội tại 0x101344de8
trong vòng lặp: 4315172328
trong nội: 4315172328
trong nội: 4315172328
trong nội: 4315172328
gọi: chức năng nội tại 0x101344de8

i: chức năng nội tại 0x101344e60
trong vòng lặp: 4315172448
trong nội: 4315172448
trong nội: 4315172448
trong nội: 4315172448
gọi: chức năng nội tại 0x101344e60

i: chức năng nội tại 0x101344ed8
trong vòng lặp: 4315172568
trong nội: 4315172568
trong nội: 4315172568
trong nội: 4315172568
gọi: chức năng nội tại 0x101344ed8

+3

bạn chỉ gặp thẩm lười biếng của 'i' –

+0

liên quan: https://stackoverflow.com/questions/42805800/generator-comprehension-different-output-from-list-comprehension –

+0

Đây không phải là có liên quan để đánh giá lười biếng, đó là một vấn đề ngữ cảnh. Đánh giá lười biếng là về đánh giá chỉ khi cần thiết, không phải ở đâu. –

Trả lời

1

Biến i trả lại trong chức năng inner giữ giá trị của nó từ ngữ cảnh cuối cùng được gán.

Nếu bạn gỡ lỗi mã, sử dụng điểm ngắt bên trong hàm inner, ảnh sẽ trở nên rõ ràng hơn nếu chọn khung/ngữ cảnh trước đó (phía dưới bên trái trong hình) trước khi gọi hàm.

Khi bạn sử dụng i, nó được gán bên trong số for thứ hai, vì vậy nó sẽ có một hàm làm giá trị của nó (được đánh dấu màu vàng trong Hình 1).

Figure 1

Bây giờ, nếu bạn sử dụng j, biến i sẽ giữ giá trị cuối cùng của nó từ bối cảnh theo thời gian: các for trên danh sách (Hình 2).

Figure 2

1

Thực tế, khi bạn sử dụng j trong kết quả, biến i vẫn là 4, do sau vòng lặp đầu tiên, tôi giữ nguyên số 4;

Nhưng nếu bạn sử dụng i trong kết quả, tôi tham khảo các hàm được lưu trữ bên trong kết quả. Tôi không cố định cho đến khi bạn bắt đầu gọi nó. như @ Jean-François Fabre nói, đánh giá lười biếng.

Ngoài, nếu bạn muốn chức năng bên trong để lưu trữ mỗi i khi vòng 1-4, bạn nên lưu trữ i trong liên quan phạm vi, sử dụng phần chức năng;

from functools import partial 

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(i, y): 
     return i 


    results.append(partial(inner, i)) 

for i in results: 
    print(i(None)) 

này sẽ cung cấp cho bạn kết quả

1 
2 
3 
4 

đó là ý nghĩa hơn.

3

Hàm inner bạn đã xác định chứa biến miễn phí tham chiếu đến biến toàn cục i. Đây có lẽ là rõ ràng hơn trong một ví dụ như thế này:

def inner(y): 
    return i 

i = 1 
print inner(None) 

i = 2 
print inner(None) 

mà in 1 và sau đó 2

Trong ví dụ đầu tiên của bạn, tại thời điểm cuộc gọi đến inner, i có giá trị mà là chức năng và vì vậy đó là những gì được in khi i (được gọi là inner) được gọi.

Trong ví dụ thứ hai, tại thời điểm cuộc gọi đến inner, i có giá trị 4 và đó là nội dung được in khi j (là inner) được gọi.

Cách rõ ràng để thể hiện những gì bạn có thể muốn ở đây là sử dụng hàm được đánh giá một phần, như được đề xuất trong một answer khác. Một cách khác là sử dụng một hàm kèm theo để tạo ra một bao đóng. Như thế này:

results = [] 
for i in [1, 2, 3, 4]: 
    def outer(k): 
     def inner(y): 
      return k 
     return inner 
    results.append(outer(i)) 

for i in results: 
    print i(None) 

sẽ in từ 1 đến 4 như bạn có thể muốn.

Một mẹo nhỏ đôi khi được sử dụng trong Python là sử dụng các giá trị mặc định của một biến như một tế bào có chứa một giá trị:

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y, i = i): 
     return i 
    results.append(inner) 

for i in results: 
    print i(None) 

mà cũng in 1 tới 4.

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