มาทำให้คำถามง่ายขึ้น กำหนด:
def get_petters():
for animal in ['cow', 'dog', 'cat']:
def pet_function():
return "Mary pets the " + animal + "."
yield (animal, pet_function)
จากนั้นเช่นเดียวกับในคำถามเราได้รับ:
>>> 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.
แต่ถ้าเราหลีกเลี่ยงการสร้างสิ่งlist()
แรก:
>>> for name, f in get_petters():
... print(name + ":", f())
cow: Mary pets the cow.
dog: Mary pets the dog.
cat: Mary pets the cat.
เกิดอะไรขึ้น? เหตุใดความแตกต่างที่ลึกซึ้งนี้จึงเปลี่ยนผลลัพธ์ของเราอย่างสิ้นเชิง
ถ้าเราดูlist(get_petters())
มันชัดเจนจากที่อยู่หน่วยความจำที่เปลี่ยนไปซึ่งเราให้ฟังก์ชันที่แตกต่างกันสามอย่าง:
>>> 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>)]
อย่างไรก็ตามลองดูที่cell
ฟังก์ชันเหล่านี้เชื่อมโยงกับ:
>>> 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>,)
สำหรับทั้งสองลูปcell
วัตถุจะยังคงเหมือนเดิมตลอดการวนซ้ำ อย่างไรก็ตามตามที่คาดstr
ไว้การอ้างอิงที่เฉพาะเจาะจงจะแตกต่างกันไปในลูปที่สอง cell
วัตถุหมายถึงanimal
ซึ่งถูกสร้างขึ้นเมื่อget_petters()
ถูกเรียกว่า อย่างไรก็ตามanimal
การเปลี่ยนแปลงสิ่งที่str
วัตถุมันหมายถึงเป็นฟังก์ชั่นเครื่องกำเนิดไฟฟ้าวิ่ง
ในลูปแรกระหว่างการวนซ้ำแต่ละครั้งเราสร้างf
s ทั้งหมดแต่เราจะเรียกมันหลังจากที่เครื่องกำเนิดไฟฟ้าget_petters()
หมดลงอย่างสมบูรณ์และlist
ฟังก์ชันถูกสร้างขึ้นแล้ว
ในลูปที่สองระหว่างการวนซ้ำแต่ละครั้งเรากำลังหยุดget_petters()
เครื่องกำเนิดไฟฟ้าชั่วคราวและเรียกใช้f
หลังจากหยุดแต่ละครั้ง ดังนั้นเราจึงดึงค่าของanimal
ช่วงเวลานั้นในช่วงเวลาที่ฟังก์ชันเครื่องกำเนิดไฟฟ้าหยุดชั่วคราว
ดังที่ @Claudiu ให้คำตอบสำหรับคำถามที่คล้ายกัน :
มีการสร้างฟังก์ชันแยกกันสามฟังก์ชัน แต่แต่ละฟังก์ชันมีการปิดสภาพแวดล้อมที่กำหนดไว้ในกรณีนี้คือสภาวะแวดล้อมส่วนกลาง (หรือสภาพแวดล้อมของฟังก์ชันภายนอกหากวางลูปไว้ในฟังก์ชันอื่น) ตรงนี้เป็นปัญหาที่เกิดขึ้นแม้ว่า - ในสภาพแวดล้อมนี้กลายพันธุ์และการปิดทั้งหมดให้ดูที่เดียวกันanimal
animal
[หมายเหตุบรรณาธิการ: i
ถูกเปลี่ยนเป็นanimal
.]
for animal in ['cat', 'dog', 'cow']
... ฉันแน่ใจว่าจะมีคนมาอธิบายเรื่องนี้ - มันเป็นหนึ่งใน Python gotcha ของ :)