Python แสดงรายการตัววนซ้ำและตัวถัดไป (ตัววนซ้ำ)


147

พิจารณา:

>>> lst = iter([1,2,3])
>>> next(lst)
1
>>> next(lst)
2

ดังนั้นความก้าวหน้าของตัววนซ้ำก็เป็นไปตามที่คาดการณ์ไว้จัดการโดยการกลายพันธุ์วัตถุเดียวกัน

ในกรณีนี้ฉันคาดหวังว่า:

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

เพื่อข้ามทุกองค์ประกอบที่สอง: การเรียกร้องให้nextควรล่วงหน้า iterator ครั้งเดียวแล้วโทรนัยทำโดยวงควรล่วงหน้าเป็นครั้งที่สอง - iและผลของการโทรที่สองนี้จะได้รับการมอบหมายให้

มันไม่ได้ ลูปจะพิมพ์รายการทั้งหมดในรายการโดยไม่ข้ามอะไรเลย

ความคิดแรกของฉันคือว่าเรื่องนี้อาจจะเกิดขึ้นเพราะห่วงเรียกร้องiterในสิ่งที่มันจะผ่านไปและอาจให้ iterator อิสระ - iter(a) is aนี้ไม่ได้เป็นกรณีที่เรามี

ดังนั้นทำไมnextไม่ปรากฏตัวเลื่อนซ้ำในกรณีนี้?

คำตอบ:


197

สิ่งที่คุณเห็นคือล่ามสะท้อนกลับค่าส่งคืนnext()นอกเหนือจากiการพิมพ์ซ้ำแต่ละครั้ง:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0
1
2
3
4
5
6
7
8
9

ดังนั้น0ผลลัพธ์ของprint(i), 1ค่าส่งคืนจากnext(), ถูกสะท้อนโดยล่ามแบบโต้ตอบ, ฯลฯ มีเพียง 5 การวนซ้ำ, การวนซ้ำแต่ละครั้งส่งผลให้ 2 บรรทัดถูกเขียนไปยังเทอร์มินัล

หากคุณกำหนดผลลัพธ์ของnext()สิ่งต่าง ๆ ให้ทำงานตามที่คาดไว้:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    _ = next(a)
... 
0
2
4
6
8

หรือพิมพ์ข้อมูลพิเศษเพื่อแยกprint()เอาท์พุทจาก echo interpreter แบบโต้ตอบ:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print('Printing: {}'.format(i))
...    next(a)
... 
Printing: 0
1
Printing: 2
3
Printing: 4
5
Printing: 6
7
Printing: 8
9

กล่าวอีกนัยหนึ่งnext()ทำงานได้ตามที่คาดไว้ แต่เนื่องจากมันส่งคืนค่าถัดไปจากตัววนซ้ำซึ่งสะท้อนโดยล่ามแบบโต้ตอบคุณจึงเชื่อว่าลูปมีตัววนซ้ำของตัวเอง


13
ฉันไม่ได้ตระหนักถึงพฤติกรรมนี้จากล่าม ฉันดีใจที่ฉันค้นพบว่าก่อนที่จะเสียเวลามากในการสงสัยในขณะที่การแก้ปัญหาจริงบางอย่าง
brandizzi

5
... * ตาย * ที่เลวร้ายที่สุดคือฉันจำได้ว่าพูดถึงพฤติกรรมการล่ามนี้กับบางคนในสัปดาห์ที่แล้ว
lvc

น่าสนใจ ฉันลอง i ใน a: next (a); print i และคิดว่าฉันจะข้ามไปที่ 1 และพิมพ์ 1,3,5,7,9 แต่ก็ยังคงเป็น 0,2,4,6,8 ทำไม?
user2290820

3
iได้รับมอบหมายแล้ว next(a)หมายความว่าการทำซ้ำครั้งถัดไป2ได้รับมอบหมายiจากนั้นให้คุณย้ายaไปพิมพ์อีกครั้งiฯลฯ
Martijn Pieters

1
สิ่งนี้จะไม่ทำงานหาก n เป็นคี่ - StopIterationexcepetio nis จะเพิ่มขึ้นเมื่อnext(a)มีการเรียกใช้หลังจากรายการถูกทำให้ยุ่งเหยิง
Raf

13

สิ่งที่เกิดขึ้นคือnext(a)ส่งคืนค่าถัดไปของ a ซึ่งพิมพ์ไปยังคอนโซลเนื่องจากไม่ได้รับผลกระทบ

สิ่งที่คุณสามารถทำได้คือส่งผลกระทบต่อตัวแปรด้วยค่านี้:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    b=next(a)
...
0
2
4
6
8

8

ฉันพบคำตอบที่มีอยู่สับสนเล็กน้อยเพราะพวกเขาเพียงระบุสิ่งที่ลึกลับในตัวอย่างโค้ดโดยอ้อม: ทั้ง "print i" และ "next (a)" ทำให้เกิดผลลัพธ์ที่จะพิมพ์

เนื่องจากพวกเขากำลังพิมพ์องค์ประกอบทางเลือกของลำดับเดิมและไม่คาดคิดว่าคำสั่ง "next (a)" กำลังพิมพ์จึงปรากฏราวกับว่าคำสั่ง "print i" กำลังพิมพ์ค่าทั้งหมด

ในความสว่างนั้นจะชัดเจนมากขึ้นว่าการกำหนดผลลัพธ์ของ "next (a)" ให้กับตัวแปรยับยั้งการพิมพ์ผลลัพธ์ 'ดังนั้นเพื่อเพียงแค่ค่าทางเลือกที่พิมพ์ตัวแปรลูป "i" ในทำนองเดียวกันการทำให้คำสั่ง "พิมพ์" ส่งเสียงบางอย่างที่มีความชัดเจนยิ่งขึ้นทำให้เกิดความสับสน

(หนึ่งในคำตอบที่มีอยู่จะลบล้างคำตอบอื่น ๆ เพราะคำตอบนั้นมีการประเมินโค้ดตัวอย่างเป็นบล็อกเพื่อให้ล่ามไม่ได้รายงานค่ากลางสำหรับ "next (a)")

โดยทั่วไปสิ่งที่ล่อลวงในการตอบคำถามโดยทั่วไปคือความชัดเจนเกี่ยวกับสิ่งที่ชัดเจนเมื่อคุณรู้คำตอบ มันอาจจะเข้าใจยาก คำติชมการวิพากษ์วิจารณ์เช่นเดียวกันเมื่อคุณเข้าใจพวกเขา มันน่าสนใจ ...


2

มีบางอย่างผิดปกติกับ Python / คอมพิวเตอร์ของคุณ

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

>>> 
0
2
4
6
8

ทำงานเหมือนที่คาดไว้

ทดสอบใน Python 2.7 และ Python 3+ ทำงานได้อย่างถูกต้องทั้งใน


5
ฉันได้รับผลลัพธ์เช่นเดียวกับ @lvc (เฉพาะ IDLE แต่เมื่อดำเนินการตามสคริปต์ฉันจะได้รับสิ่งนี้))
jamylak

3
@Inbar Rose เฉพาะเมื่อคุณเรียกใช้เป็นสคริปต์
Quintec

1
มันเป็นพฤติกรรมของการใส่รหัสผ่านเปลือกโต้ตอบ ถ้าฟังก์ชั่นคืนค่าโดยไม่ต้องใช้ล่ามจะพิมพ์ลงในเชลล์เพื่อส่งออก debug
Reishin

2

สำหรับผู้ที่ยังไม่เข้าใจ

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0 # print(i) printed this
1 # next(a) printed this
2 # print(i) printed this
3 # next(a) printed this
4 # print(i) printed this
5 # next(a) printed this
6 # print(i) printed this
7 # next(a) printed this
8 # print(i) printed this
9 # next(a) printed this

ตามที่คนอื่นพูดไปแล้วให้nextเพิ่มตัววนซ้ำ 1 ตามที่คาดไว้ การกำหนดค่าที่ส่งคืนให้กับตัวแปรนั้นไม่ได้เปลี่ยนแปลงพฤติกรรมของมันอย่างน่าอัศจรรย์


1

มันจะทำงานในแบบที่คุณต้องการถ้าเรียกว่าเป็นฟังก์ชั่น:

>>> def test():
...     a = iter(list(range(10)))
...     for i in a:
...         print(i)
...         next(a)
... 
>>> test()
0
2
4
6
8
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.