Mari sederhanakan pertanyaannya. Menetapkan:
def get_petters():
for animal in ['cow', 'dog', 'cat']:
def pet_function():
return "Mary pets the " + animal + "."
yield (animal, pet_function)
Kemudian, seperti dalam pertanyaan, kita mendapatkan:
>>> for name, f in list(get_petters()):
... print(name + ":", f())
cow: Mary pets the cat.
dog: Mary pets the cat.
cat: Mary pets the cat.
Tetapi jika kita menghindari membuat yang list()pertama:
>>> for name, f in get_petters():
... print(name + ":", f())
cow: Mary pets the cow.
dog: Mary pets the dog.
cat: Mary pets the cat.
Apa yang sedang terjadi? Mengapa perbedaan halus ini benar-benar mengubah hasil kami?
Jika kita lihat list(get_petters()), jelas dari alamat memori yang berubah bahwa kita memang menghasilkan tiga fungsi yang berbeda:
>>> list(get_petters())
[('cow', <function get_petters.<locals>.pet_function at 0x7ff2b988d790>),
('dog', <function get_petters.<locals>.pet_function at 0x7ff2c18f51f0>),
('cat', <function get_petters.<locals>.pet_function at 0x7ff2c14a9f70>)]
Namun, perhatikan cellbahwa fungsi-fungsi ini terikat:
>>> for _, f in list(get_petters()):
... print(f(), f.__closure__)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
>>> for _, f in get_petters():
... print(f(), f.__closure__)
Mary pets the cow. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c1a95670>,)
Mary pets the dog. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c1a952f0>,)
Mary pets the cat. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c3f437f0>,)
Untuk kedua loop, cellobjek tetap sama selama iterasi. Namun, seperti yang diharapkan, strreferensi spesifik itu bervariasi di loop kedua. The cellobjek mengacu pada animal, yang dibuat ketika get_petters()disebut. Namun, animalmengubah apastr objek yang dirujuknya saat fungsi generator berjalan .
Di loop pertama, selama setiap iterasi, kami membuat semua file f s, tetapi kita hanya memanggilnya setelah generator get_petters()benar-benar habis dan a listdari fungsi sudah dibuat.
Di loop kedua, selama setiap iterasi, kami menjeda file get_petters() generator dan memanggil fsetelah setiap jeda. Jadi, kami akhirnya mengambil nilai animalpada saat fungsi generator dihentikan sementara.
Seperti yang @Claudiu berikan untuk menjawab pertanyaan serupa :
Tiga fungsi terpisah dibuat, tetapi masing-masing memiliki penutupan lingkungan tempat mereka didefinisikan - dalam hal ini, lingkungan global (atau lingkungan fungsi luar jika loop ditempatkan di dalam fungsi lain). Namun, inilah masalahnya - di lingkungan ini,animal bermutasi, dan closure semuanya mengacu pada hal yang sama animal.
[Catatan editor: itelah diubah menjadi animal.]
for animal in ['cat', 'dog', 'cow']... Saya yakin seseorang akan datang dan menjelaskan hal ini - ini salah satu dari Python gotcha :)