iterator, iterable และ iteration คืออะไรกันแน่?


442

คำจำกัดความพื้นฐานที่สุดของ "iterable", "iterator" และ "iteration" ใน Python คืออะไร?

ฉันได้อ่านคำจำกัดความหลายคำ แต่ฉันไม่สามารถระบุความหมายที่แน่นอนได้เนื่องจากมันยังไม่จม

ใครสามารถช่วยฉันด้วยคำจำกัดความ 3 คำในคนธรรมดา?

คำตอบ:


530

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

ใน Python iterableและiteratorมีความหมายเฉพาะ

iterableเป็นวัตถุที่มีนักการ__iter__วิธีการที่ส่งกลับiteratorหรือที่กำหนด__getitem__วิธีการที่สามารถใช้ดัชนีลำดับเริ่มต้นจากศูนย์ (และทำให้เกิดIndexErrorเมื่อดัชนีจะไม่ถูกต้อง) ดังนั้นการวนซ้ำเป็นวัตถุที่คุณสามารถรับตัววนซ้ำได้

ตัววนซ้ำเป็นวัตถุที่มีเมธอดnext(Python 2) หรือ__next__(Python 3)

เมื่อใดก็ตามที่คุณใช้forลูปหรือmapหรือความเข้าใจในรายการ ฯลฯ ใน Python nextเมธอดจะถูกเรียกโดยอัตโนมัติเพื่อรับแต่ละไอเท็มจากตัววนซ้ำดังนั้นจะผ่านกระบวนการทำซ้ำการทำซ้ำ

สถานที่ที่ดีที่จะเริ่มต้นการเรียนรู้ที่จะเป็นส่วน iterators ของการกวดวิชาและส่วนประเภท iterator ประเภทมาตรฐานหน้า หลังจากที่คุณเข้าใจพื้นฐานลองส่วน iterators ของหน้าที่ Programming HOWTO


1
โปรดทราบว่าcollections.abc.AsyncIteratorการทดสอบ__aiter__และ__anext__วิธีการ นี่คือการเพิ่มใหม่ใน 3.6
Janus Troelsen

1
@jlh ทำไมจะ__len__ต้องเชื่อมโยงกับการทำซ้ำจำเป็น? การรู้ว่าความยาวของบางสิ่งจะช่วยให้คุณย้ำมันได้อย่างไร
shadowtalker

2
@shadowtalker จะช่วยให้ทราบว่าดัชนีใดที่ถูกต้องดังนั้นคุณจึงรู้ว่าสามารถใช้ดัชนีใดได้__getitem__บ้าง
jlh

4
@jlh ดูเหมือนว่าคุณกำลังเสนอพฤติกรรมการแสดงความคิดเห็นที่ผิดพลาดมาก พิจารณาว่า{'a': 'hi', 'b': 'bye'}มีความยาว 2 แต่ไม่สามารถทำดัชนีโดย 0, 1 หรือ 2
shadowtalker

2
@shadowtalker แต่ dict มี__iter__วิธีการ ฉันคิดว่า jlh หมายถึงวัตถุที่ทำซ้ำได้โดยเฉพาะเพราะพวกเขาให้คำจำกัดความ: " __getitem__วิธีการที่สามารถใช้ดัชนีตามลำดับที่เริ่มต้นจากศูนย์"
รวย

337

นี่คือคำอธิบายที่ฉันใช้ในการสอนคลาส Python:

ITERABLE คือ:

  • ทุกสิ่งที่สามารถวนซ้ำได้ (เช่นคุณสามารถวนซ้ำสตริงหรือไฟล์) หรือ
  • สิ่งใดก็ตามที่สามารถปรากฏที่ด้านขวาของ for-loop: for x in iterable: ...หรือ
  • ทุกสิ่งที่คุณสามารถโทรหาด้วยiter()จะส่งคืน ITERATOR: iter(obj)หรือ
  • วัตถุที่กำหนด__iter__ว่าจะส่งกลับ ITERATOR ที่สดใหม่หรืออาจมี__getitem__วิธีการที่เหมาะสมสำหรับการค้นหาการจัดทำดัชนี

ITERATOR เป็นวัตถุ:

  • กับรัฐที่จำได้ว่ามันอยู่ที่ไหนในช่วงการทำซ้ำ
  • ด้วย__next__วิธีการที่:
    • ส่งคืนค่าถัดไปในการวนซ้ำ
    • อัพเดตสถานะให้ชี้ไปที่ค่าถัดไป
    • สัญญาณเมื่อมีการทำโดยการเพิ่ม StopIteration
  • และนั่นคือตัวเองได้ (หมายถึงมันมี__iter__วิธีการที่ส่งคืนself)

หมายเหตุ:

  • __next__วิธีการในหลาม 3 สะกดnextในหลาม 2 และ
  • ฟังก์ชั่น builtin next()เรียกใช้วิธีการนั้นกับวัตถุที่ส่งผ่านไป

ตัวอย่างเช่น:

>>> s = 'cat'      # s is an ITERABLE
                   # s is a str object that is immutable
                   # s has no state
                   # s has a __getitem__() method 

>>> t = iter(s)    # t is an ITERATOR
                   # t has state (it starts by pointing at the "c"
                   # t has a next() method and an __iter__() method

>>> next(t)        # the next() function returns the next value and advances the state
'c'
>>> next(t)        # the next() function returns the next value and advances
'a'
>>> next(t)        # the next() function returns the next value and advances
't'
>>> next(t)        # next() raises StopIteration to signal that iteration is complete
Traceback (most recent call last):
...
StopIteration

>>> iter(t) is t   # the iterator is self-iterable

คุณหมายถึงอะไรโดย iterator ที่สดใหม่
lmiguelvargasf

13
@lmiguelvargasf "สด" เหมือนใน "ใหม่และไม่บริสุทธิ์" ซึ่งตรงข้ามกับ "หมดหรือบริโภคเพียงบางส่วน" แนวคิดคือตัววนซ้ำใหม่เริ่มต้นที่จุดเริ่มต้นในขณะที่ตัววนซ้ำที่ใช้บางส่วนจะเลือกตำแหน่งที่ปล่อยทิ้งไว้
Raymond Hettinger

สัญลักษณ์แสดงหัวข้อย่อยที่ 2, 3 และ 4 ของคุณระบุสิ่งที่คุณหมายถึงอย่างชัดเจนในรูปแบบของการสร้างหรือการสร้างหรือการเรียกใช้เมธอด แต่กระสุนแรก ("อะไรก็ได้ที่สามารถคล้องกันได้") ไม่มีความชัดเจนนั้น นอกจากนี้กระสุนนัดที่ 1 ดูเหมือนจะมีการทับซ้อนกับกระสุนนัดที่ 2 เนื่องจากกระสุนนัดที่ 2 นั้นเกี่ยวกับforลูปและกระสุนนัดที่ 1 นั้นเกี่ยวกับ "การวนซ้ำ" คุณช่วยพูดถึงสิ่งเหล่านี้ได้มั้ย
fountainhead

2
โปรดลองคิดใหม่อีกครั้งว่า "ทุกสิ่งที่คุณสามารถโทรหาiter()" เป็น "อะไรก็ได้ที่คุณสามารถส่งผ่านไปยังiter()"
Fountainhead

98

คำตอบข้างต้นนั้นยอดเยี่ยม แต่สิ่งที่ฉันเห็นส่วนใหญ่ไม่เน้นความแตกต่างสำหรับคนอย่างฉัน

นอกจากนี้ผู้คนมักจะได้รับ "เกินไป Pythonic" โดยการใส่คำนิยามเช่น "X เป็นวัตถุที่มี__foo__()วิธีการ" ก่อน คำจำกัดความดังกล่าวถูกต้อง - พวกมันอยู่บนพื้นฐานของปรัชญาการพิมพ์เป็ด แต่การมุ่งเน้นไปที่วิธีการมีแนวโน้มที่จะได้รับเมื่อพยายามที่จะเข้าใจแนวคิดในความเรียบง่าย

ดังนั้นฉันจะเพิ่มรุ่นของฉัน


ในภาษาธรรมชาติ

  • การวนซ้ำเป็นกระบวนการในการรับองค์ประกอบหนึ่งครั้งในหนึ่งแถวขององค์ประกอบ

ใน Python

  • iterableเป็นวัตถุที่ดีดี iterable ซึ่งใส่หมายความว่ามันสามารถใช้ในการทำซ้ำเช่นกับforวน อย่างไร? โดยใช้ตัววนซ้ำ iteratorฉันจะอธิบายด้านล่าง

  • ... ในขณะที่ตัววนซ้ำเป็นวัตถุที่กำหนดวิธีการทำซ้ำจริง ๆ - โดยเฉพาะสิ่งที่เป็นองค์ประกอบต่อไป นั่นเป็นเหตุผลว่าทำไมมันต้องมี next()วิธีการ

ตัวทำซ้ำนั้นเองก็สามารถทำซ้ำได้โดยมีความแตกต่างว่า__iter__()วิธีการของพวกเขาจะส่งคืนวัตถุเดียวกัน ( self) ไม่ว่ารายการนั้นจะถูกใช้ไปnext()แล้วหรือไม่โดยการโทรไปก่อนหน้า


ดังนั้นนักแปล Python จะคิดอย่างไรเมื่อเห็นfor x in obj:คำสั่ง?

ดูสิ forห่วง ดูเหมือนว่าเป็นงานสำหรับตัววนซ้ำ ... ลองหาหนึ่ง ... มีobjผู้ชายคนนี้มาถามเขาสิ

"นายobjคุณมีตัววนซ้ำของคุณหรือไม่" (... การโทรiter(obj)ซึ่งการโทร obj.__iter__()ซึ่งมีความสุขนั้นจะทำหน้าที่เป็นตัววนซ้ำตัวใหม่ที่เปล่งประกาย_i )

ตกลงนั่นเป็นเรื่องง่าย ... เริ่มทำซ้ำกันแล้ว ( x = _i.next()... x = _i.next()... )

เนื่องจากนายobjประสบความสำเร็จในการทดสอบนี้ (โดยให้วิธีการคืนค่าตัวทำซ้ำที่ถูกต้อง) เราจึงตอบแทนเขาด้วยคำคุณศัพท์: ตอนนี้คุณสามารถเรียกเขาได้ว่า "นายน่าเชื่อถือobj "

อย่างไรก็ตามในกรณีปกติคุณไม่ได้รับประโยชน์จากการมีตัววนซ้ำและการแยกซ้ำ ดังนั้นคุณจึงกำหนดวัตถุเดียวเท่านั้นซึ่งเป็นตัววนซ้ำของมันเอง (หลามไม่ได้สนใจจริงๆที่_iส่งออกมาobjไม่ได้เป็นสิ่งที่มันวาว แต่เพียงobjตัวเอง)

นี่คือเหตุผลในตัวอย่างส่วนใหญ่ที่ฉันเห็น (และสิ่งที่ทำให้ฉันสับสนซ้ำแล้วซ้ำอีก) คุณสามารถดู:

class IterableExample(object):

    def __iter__(self):
        return self

    def next(self):
        pass

แทน

class Iterator(object):
    def next(self):
        pass

class Iterable(object):
    def __iter__(self):
        return Iterator()

มีหลายกรณีที่เมื่อคุณได้รับประโยชน์จากการแยกตัววนซ้ำจากการทำซ้ำเช่นเมื่อคุณต้องการมีหนึ่งแถวของรายการ แต่มี "เคอร์เซอร์" มากกว่า ตัวอย่างเช่นเมื่อคุณต้องการทำงานกับองค์ประกอบ "ปัจจุบัน" และ "เตรียมพร้อม" คุณสามารถแยกตัววนซ้ำสำหรับทั้งคู่ได้ หรือหลายเธรดที่ดึงจากรายการขนาดใหญ่: แต่ละรายการสามารถมีตัววนซ้ำของตัวเองเพื่อสำรวจรายการทั้งหมด ดูที่@ Raymond'sและ@ glglgl'sคำตอบด้านบน

ลองนึกภาพสิ่งที่คุณสามารถทำได้:

class SmartIterableExample(object):

    def create_iterator(self):
        # An amazingly powerful yet simple way to create arbitrary
        # iterator, utilizing object state (or not, if you are fan
        # of functional), magic and nuclear waste--no kittens hurt.
        pass    # don't forget to add the next() method

    def __iter__(self):
        return self.create_iterator()

หมายเหตุ:

  • ฉันจะทำซ้ำอีกครั้ง: iterator ไม่ iterable Iterator ไม่สามารถใช้เป็น "แหล่ง" ในforวง สิ่งที่forต้องการเป็นหลักคือ__iter__() (ที่คืนสิ่งที่มีnext())

  • แน่นอนว่าforไม่ใช่การวนซ้ำซ้ำเท่านั้นดังนั้นข้างบนจึงใช้กับการสร้างอื่น ๆ ด้วย ( while... )

  • Iterator next()สามารถใช้ StopIteration เพื่อหยุดการวนซ้ำ ไม่จำเป็นต้องใช้มันสามารถย้ำตลอดไปหรือใช้วิธีการอื่น

  • ในกระบวนการคิด "ข้างต้น_iไม่มีอยู่จริง ฉันใช้ชื่อนั้น

  • : มีการเปลี่ยนแปลงเล็ก ๆ ในหลาม 3.x เป็นnext()วิธีการ (ไม่ได้ในตัว) __next__()ตอนนี้ต้องเรียกว่า ใช่มันควรจะเป็นอย่างนั้นมาตลอด

  • คุณสามารถคิดแบบนี้ได้: iterable มีข้อมูลตัววนซ้ำดึงรายการถัดไป

ข้อจำกัดความรับผิดชอบ:ฉันไม่ใช่นักพัฒนาของ Python ล่ามดังนั้นฉันจึงไม่รู้จริงๆว่าล่าม "คิด" เพลงเหล่านี้เป็นเพียงการสาธิตวิธีที่ฉันเข้าใจหัวข้อจากคำอธิบายอื่น ๆ การทดลองและประสบการณ์ชีวิตจริงของมือใหม่ Python


1
นี่ยอดเยี่ยม - แต่ฉันยังสับสนอยู่เล็กน้อย ฉันคิดว่ากล่องสีเหลืองของคุณกำลังบอกว่าการforวนซ้ำต้องมีตัววนซ้ำ ("Look, for for loop ดูเหมือนว่างานสำหรับตัววนซ้ำ ... มารวมกัน" แต่แล้วคุณพูดในหมายเหตุท้ายว่า "Iterator ไม่สามารถใช้เป็นแหล่งในforลูป" ... ?
Racing Tadpole

ทำไมคุณถึงใส่passรหัสลงไปในnextคำจำกัดความเหล่านั้น? ฉันจะสมมติว่าคุณแค่หมายความว่ามีคนต้องใช้วิธีในการรับคนต่อไปเนื่องจากคนต่อไปจะต้องส่งคืนบางสิ่งบางอย่าง
nealmcb

@nealmcb ใช่ฉันคิดว่านั่นคือสิ่งที่ผ่านมาฉันหมายถึง (นั่นคือสิ่งที่passเป็นหลังจากทั้งหมด.)
Alois Mahdal

@AloisMahdal Ahh ฉันไม่เคยเห็นที่ใช้มาก่อน เมื่อฉันเห็นpassฉันคิดว่ามันมีเหตุผลวากยสัมพันธ์ ฉันเพิ่งพบคำตอบที่วัตถุรูปไข่ซึ่งน่าสนใจมาก: คุณสามารถใช้...เพื่อระบุบล็อก "todo ภายหลัง" NotImplementedยังมีอยู่
nealmcb

ในขณะที่ฉันชอบที่คุณกำลังเน้นความแตกต่างระหว่าง iterator และ iterable คำตอบนี้ขัดแย้งกับตัวเอง ก่อนอื่นคุณเขียนว่า 'Iterators นั้นเป็นตัวทำซ้ำได้เอง' (ซึ่งตรงกับสิ่งที่เขียนในเอกสาร Python ) แต่หลังจากนั้นเมื่อคุณเขียน: ' iterator ไม่สามารถทำซ้ำได้ Iterator ไม่สามารถใช้เป็น "source" ในforloop ' ฉันได้รับคำตอบจากคุณและชอบเป็นอย่างอื่น แต่ฉันคิดว่ามันจะได้ประโยชน์จากการแก้ไข
รวย

22

iterable เป็นวัตถุที่มี__iter__()วิธีการ มันอาจจะวนซ้ำหลายครั้งเช่นlist()s และtuple()s

ตัววนซ้ำเป็นวัตถุที่วนซ้ำ มันถูกส่งคืนโดย__iter__()เมธอดส่งคืนตัวเองผ่าน__iter__()เมธอดของตัวเองและมีnext()เมธอด ( __next__()ใน 3.x)

การย้ำเป็นกระบวนการของการเรียกการตอบnext()สนองนี้ จนกว่ามันจะเพิ่ม__next__()StopIteration

ตัวอย่าง:

>>> a = [1, 2, 3] # iterable
>>> b1 = iter(a) # iterator 1
>>> b2 = iter(a) # iterator 2, independent of b1
>>> next(b1)
1
>>> next(b1)
2
>>> next(b2) # start over, as it is the first call to b2
1
>>> next(b1)
3
>>> next(b1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> b1 = iter(a) # new one, start over
>>> next(b1)
1

ดังนั้นจริงๆมันเป็นเพียงวัตถุที่ส่งผ่านภาชนะ? สิ่งนี้จะเป็นประโยชน์หรือไม่?
thechrishaddad

บ่อยครั้ง แต่ไม่เสมอไป เคอร์เซอร์ตัวกำเนิดไฟล์หรือฐานข้อมูลสามารถทำซ้ำได้เพียงครั้งเดียวจึงเป็นตัววนซ้ำของตัวเอง
glglgl

ฉันเดา b2 ไม่จำเป็นต้องเป็นอิสระจาก b1? สำหรับกรณีพิเศษนี้ก็อิสระแน่ใจว่าผมสามารถทำให้มันไม่ได้เป็นอิสระ Iterableแต่ยังเป็นที่ถูกต้อง
Bin

@Bin ใช่ ในฐานะที่เป็นและIteratorอยู่เสมอIterableและเป็นของตัวเองIterator, สองสายของiter()ไม่จำเป็นต้องให้สองอิสระIterators
glglgl

13

นี่คือสูตรโกงของฉัน:

 sequence
  +
  |
  v
   def __getitem__(self, index: int):
  +    ...
  |    raise IndexError
  |
  |
  |              def __iter__(self):
  |             +     ...
  |             |     return <iterator>
  |             |
  |             |
  +--> or <-----+        def __next__(self):
       +        |       +    ...
       |        |       |    raise StopIteration
       v        |       |
    iterable    |       |
           +    |       |
           |    |       v
           |    +----> and +-------> iterator
           |                               ^
           v                               |
   iter(<iterable>) +----------------------+
                                           |
   def generator():                        |
  +    yield 1                             |
  |                 generator_expression +-+
  |                                        |
  +-> generator() +-> generator_iterator +-+

คำถาม: คุณเห็นไหมว่า ...

  1. ตัววนซ้ำทุกตัวซ้ำได้หรือไม่
  2. __iter__()วิธีการของวัตถุภาชนะสามารถนำมาใช้เป็นเครื่องกำเนิดไฟฟ้าหรือไม่?
  3. การทำซ้ำที่มี__next__วิธีการไม่จำเป็นต้องเป็นตัววนซ้ำ?

คำตอบ:

  1. ตัววนซ้ำทุกตัวต้องมี __iter__วิธีการ การมี__iter__เพียงพอที่จะทำซ้ำได้ ดังนั้นตัววนซ้ำทั้งหมดจึงซ้ำได้
  2. เมื่อ__iter__ถูกเรียกมันควรจะส่งคืนตัววนซ้ำ ( return <iterator>ในแผนภาพด้านบน) การเรียกตัวสร้างคืนค่าตัวสร้างตัววนซ้ำซึ่งเป็นชนิดตัววนซ้ำ

    class Iterable1:
        def __iter__(self):
            # a method (which is a function defined inside a class body)
            # calling iter() converts iterable (tuple) to iterator
            return iter((1,2,3))
    
    class Iterable2:
        def __iter__(self):
            # a generator
            for i in (1, 2, 3):
                yield i
    
    class Iterable3:
        def __iter__(self):
            # with PEP 380 syntax
            yield from (1, 2, 3)
    
    # passes
    assert list(Iterable1()) == list(Iterable2()) == list(Iterable3()) == [1, 2, 3]
  3. นี่คือตัวอย่าง:

    class MyIterable:
    
        def __init__(self):
            self.n = 0
    
        def __getitem__(self, index: int):
            return (1, 2, 3)[index]
    
        def __next__(self):
            n = self.n = self.n + 1
            if n > 3:
                raise StopIteration
            return n
    
    # if you can iter it without raising a TypeError, then it's an iterable.
    iter(MyIterable())
    
    # but obviously `MyIterable()` is not an iterator since it does not have
    # an `__iter__` method.
    from collections.abc import Iterator
    assert isinstance(MyIterable(), Iterator)  # AssertionError

1
ในการตอบคำถามฉันเข้าใจเพียงสัญลักษณ์แสดงหัวข้อแรก เช่นตัววนซ้ำกลายเป็นตัววนซ้ำตามที่มี__iter__เมธอด คุณช่วยอธิบายรายละเอียดเกี่ยวกับประเด็นที่ 2 และ 3 ได้
ไหม

@AnV: เท่าที่ฉันเข้าใจ: อีกครั้ง 2: __iter__()ส่งคืนตัววนซ้ำ เครื่องกำเนิดเป็นตัววนซ้ำดังนั้นจึงสามารถใช้เพื่อจุดประสงค์นี้ได้ อีก 3 .: ฉันเท่านั้นที่สามารถคาดเดาที่นี่ แต่ผมคิดว่าถ้า__iter__()ขาดหายไปหรือไม่กลับselfก็ไม่ได้เป็น iterator เพราะ iterator ของมีการกลับมา__iter__() self
glglgl

10

ฉันไม่รู้ว่ามันช่วยใครได้ไหม แต่ฉันชอบที่จะนึกภาพแนวคิดในหัวของฉันให้เข้าใจพวกเขาดีขึ้น ดังนั้นเมื่อฉันมีลูกชายตัวน้อยฉันจึงเห็นภาพแนวคิดแบบวนซ้ำ / ตัววนซ้ำด้วยอิฐและกระดาษสีขาว

สมมติว่าเราอยู่ในห้องมืดและบนพื้นเรามีอิฐสำหรับลูกชายของฉัน อิฐที่มีขนาดแตกต่างกันสีไม่สำคัญ สมมติว่าเรามี 5 อิฐเหมือนพวกนั้น บรรดา 5 อิฐสามารถอธิบายเป็นวัตถุ - พูดให้ของชุดอิฐ เราสามารถทำสิ่งต่างๆได้ด้วยชุดอิฐนี้ - สามารถเลือกหนึ่งแล้วใช้เวลาวินาทีแล้วก็สามสามารถเปลี่ยนสถานที่ของอิฐวางอิฐก้อนแรกเหนือที่สอง เราสามารถทำสิ่งต่าง ๆ ได้หลายอย่างกับสิ่งเหล่านั้น ดังนั้นชุดอิฐนี้เป็นวัตถุหรือลำดับที่น่าสนใจในขณะที่เราสามารถผ่านอิฐแต่ละก้อนและทำอะไรกับมันได้ เราสามารถทำมันเหมือนลูกชายตัวน้อยของฉัน - เราสามารถเล่นกับหนึ่งอิฐในเวลา ดังนั้นฉันจึงจินตนาการว่าชุดอิฐนี้เป็นอีกครั้งiterable

ตอนนี้จำไว้ว่าเราอยู่ในห้องมืด หรือเกือบมืด สิ่งนั้นคือเราไม่เห็นก้อนอิฐเหล่านั้นสีอะไรรูปร่างอะไร ฯลฯ ดังนั้นแม้ว่าเราต้องการทำอะไรกับพวกมัน - หรือทำซ้ำ ๆ ผ่านพวกเขา - เราไม่รู้จริงๆว่ามันเป็นอย่างไรและเพราะอะไร มืดเกินไป

สิ่งที่เราสามารถทำได้คือใกล้กับอิฐก้อนแรก - ในฐานะที่เป็นส่วนประกอบของชุดอิฐ - เราสามารถใส่กระดาษขาวฟลูออเรสเซนต์ชิ้นหนึ่งเพื่อให้เราได้เห็นว่าองค์ประกอบอิฐก้อนแรกอยู่ที่ไหน และทุกครั้งที่เรานำอิฐจากชุดเราเปลี่ยนแผ่นกระดาษสีขาวเป็นอิฐก้อนถัดไปเพื่อให้สามารถมองเห็นได้ในห้องมืด ชิ้นนี้สีขาวของกระดาษเป็นอะไรมากไปกว่าiterator มันเป็นวัตถุเช่นกัน แต่วัตถุกับสิ่งที่เราสามารถทำงานและเล่นกับองค์ประกอบของวัตถุที่ทำซ้ำได้ของเรา - ชุดอิฐ

โดยวิธีนี้จะอธิบายความผิดพลาดเริ่มแรกของฉันเมื่อฉันลองทำสิ่งต่อไปนี้ใน IDLE และรับ TypeError:

 >>> X = [1,2,3,4,5]
 >>> next(X)
 Traceback (most recent call last):
    File "<pyshell#19>", line 1, in <module>
      next(X)
 TypeError: 'list' object is not an iterator

List X นี่คือชุดอิฐของเรา แต่ไม่ใช่กระดาษขาว ฉันต้องการค้นหาตัววนซ้ำก่อน:

>>> X = [1,2,3,4,5]
>>> bricks_kit = [1,2,3,4,5]
>>> white_piece_of_paper = iter(bricks_kit)
>>> next(white_piece_of_paper)
1
>>> next(white_piece_of_paper)
2
>>>

ไม่ทราบว่ามันช่วย แต่มันช่วยฉัน หากใครบางคนสามารถยืนยัน / แก้ไขการสร้างภาพของแนวคิดฉันจะขอบคุณ มันจะช่วยให้ฉันเรียนรู้เพิ่มเติม


6

พูดซ้ำได้ : - สิ่งที่สามารถทำซ้ำได้คือทำซ้ำได้ เช่นลำดับเช่นรายการสตริง ฯลฯ นอกจากนี้ยังมีทั้ง__getitem__วิธีการหรือ__iter__วิธีการ ตอนนี้ถ้าเราใช้iter()ฟังก์ชั่นกับวัตถุนั้นเราจะได้ตัววนซ้ำ

Iterator : - เมื่อเราได้รับวัตถุ iterator จากiter()ฟังก์ชั่น; เราเรียก__next__()วิธีการ (ใน python3) หรือเพียงแค่next()(ใน python2) เพื่อรับองค์ประกอบทีละ คลาสหรืออินสแตนซ์ของคลาสนี้เรียกว่าตัววนซ้ำ

จากเอกสาร: -

การใช้ตัววนซ้ำจะแพร่กระจายและรวม Python เบื้องหลังคำสั่งสำหรับการเรียกใช้  iter() บนวัตถุคอนเทนเนอร์ ฟังก์ชั่นส่งกลับวัตถุตัววนซ้ำที่กำหนดวิธีการ  __next__() เข้าถึงองค์ประกอบในภาชนะหนึ่งครั้ง เมื่อไม่มีองค์ประกอบเพิ่มเติม  __next__() ให้ยกข้อยกเว้น StopIteration ซึ่งบอกให้ for for loop สิ้นสุดลง คุณสามารถเรียก  __next__() ใช้เมธอดได้โดยใช้  next() ฟังก์ชันในตัว ตัวอย่างนี้แสดงวิธีการทำงานทั้งหมด:

>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    next(it)
StopIteration

ตัวอย่างของคลาส: -

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __iter__(self):
        return self
    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]


>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
...     print(char)
...
m
a
p
s

4

ฉันไม่คิดว่าคุณจะได้รับเอกสารที่ง่ายกว่านี้มากนักอย่างไรก็ตามฉันจะพยายาม:

  • Iterableเป็นสิ่งที่สามารถทำซ้ำได้ ในทางปฏิบัติมันมักจะหมายถึงลำดับเช่นสิ่งที่มีจุดเริ่มต้นและจุดสิ้นสุดและวิธีการผ่านรายการทั้งหมดในนั้น
  • คุณสามารถคิดIteratorเป็นผู้ช่วยที่หลอกวิธีการ (หรือหลอกแอตทริบิวต์) ที่ให้ (หรือถือ) ต่อไป (หรือก่อน) รายการในiterable (ในทางปฏิบัติมันเป็นเพียงวัตถุที่กำหนดวิธีการnext())

  • การทำซ้ำอาจอธิบายได้ดีที่สุดโดยคำจำกัดความ Merriam-Webster ของคำว่า :

b: การทำซ้ำลำดับของคอมพิวเตอร์สั่งจำนวนครั้งที่ระบุหรือจนกว่าจะมีเงื่อนไข - เปรียบเทียบการสอบถามซ้ำ


3
iterable = [1, 2] 

iterator = iter(iterable)

print(iterator.__next__())   

print(iterator.__next__())   

ดังนั้น,

  1. iterableเป็นวัตถุที่สามารถวนซ้ำได้ เช่นรายการสตริงสิ่งอันดับ ฯลฯ

  2. การใช้iterฟังก์ชั่นบนiterableวัตถุของเราจะส่งคืนวัตถุตัววนซ้ำ

  3. ตอนนี้วัตถุตัววนซ้ำมีวิธีการตั้งชื่อ__next__(ใน Python 3 หรือเพียงแค่nextใน Python 2) ซึ่งคุณสามารถเข้าถึงแต่ละองค์ประกอบของ iterable

ดังนั้นเอาท์พุทของรหัสข้างต้นจะเป็น:

1

2


3

Iterablesมี__iter__เมธอดที่สร้างตัววนซ้ำใหม่ทุกครั้ง

Iteratorsใช้__next__วิธีการที่ส่งกลับแต่ละรายการและ__iter__วิธีที่ส่งกลับselfวิธีการที่ผลตอบแทน

ดังนั้นตัววนซ้ำก็ซ้ำได้ แต่ตัววนซ้ำไม่ใช่ตัววนซ้ำ

Luciano Ramalho, Python อย่างคล่องแคล่ว


2

ก่อนจัดการกับ iterables และ iterator ปัจจัยหลักที่ตัดสินใจ iterable และ iterator นั้นเป็นลำดับ

ลำดับ: ลำดับคือการรวบรวมข้อมูล

Iterable: Iterable เป็นวัตถุประเภทลำดับที่รองรับ__iter__วิธีการ

วิธี Iter: วิธี Iter ใช้ลำดับเป็นอินพุตและสร้างวัตถุที่เรียกว่า iterator

Iterator: Iterator เป็นวัตถุที่เรียกใช้วิธีการต่อไปและตามลำดับ ในการเรียกใช้เมธอดถัดไปมันจะคืนค่าวัตถุที่มันเคลื่อนที่ในปัจจุบัน

ตัวอย่าง:

x=[1,2,3,4]

x คือลำดับซึ่งประกอบด้วยการรวบรวมข้อมูล

y=iter(x)

ในการเรียกiter(x)มันจะคืนค่าตัววนซ้ำเฉพาะเมื่อวัตถุ x มีเมธอด iter มิฉะนั้นจะทำให้เกิดข้อยกเว้นถ้ามันส่งกลับตัววนซ้ำแล้ว y จะถูกกำหนดเช่นนี้:

y=[1,2,3,4]

เนื่องจาก y เป็นตัววนซ้ำดังนั้นจึงรองรับnext()วิธีการ

ในการเรียกใช้วิธีการถัดไปมันจะส่งคืนองค์ประกอบแต่ละรายการหนึ่งโดยหนึ่ง

หลังจากส่งคืนองค์ประกอบสุดท้ายของลำดับหากเราเรียกวิธีการถัดไปอีกครั้งจะทำให้เกิดข้อผิดพลาด StopIteration

ตัวอย่าง:

>>> y.next()
1
>>> y.next()
2
>>> y.next()
3
>>> y.next()
4
>>> y.next()
StopIteration

แค่การสังเกต: y = iter (x) ไม่ใช่ y = [1,2,3,4] เนื่องจาก y ตอนนี้เป็นวัตถุตัววนซ้ำ บางทีคุณควรเพิ่มความคิดเห็นเพื่อชี้แจงว่าไม่ใช่รายการ แต่เป็นวัตถุตัววนซ้ำหรือเปลี่ยนการเป็นตัวแทน
coelhudo

-6

ใน Python ทุกอย่างเป็นวัตถุ เมื่อมีการบอกว่าวัตถุนั้นสามารถทำซ้ำได้หมายความว่าคุณสามารถผ่านวัตถุ (เช่นการทำซ้ำ) เป็นคอลเล็กชันได้

ตัวอย่างของอาร์เรย์สามารถใช้ซ้ำได้ คุณสามารถก้าวผ่านพวกเขาด้วยการวนรอบและจากดัชนี 0 ถึงดัชนี n และ n คือความยาวของวัตถุอาร์เรย์ลบ 1

พจนานุกรม (คู่ของคีย์ / ค่าที่เรียกว่าอาเรย์แบบเชื่อมโยง) สามารถทำซ้ำได้ คุณสามารถก้าวผ่านกุญแจของพวกเขา

เห็นได้ชัดว่าวัตถุที่ไม่ใช่คอลเลกชันจะไม่ iterable ตัวอย่างวัตถุบูลมีค่าเดียวคือจริงหรือเท็จ มันไม่สามารถทำซ้ำได้ (มันจะไม่ทำให้รู้สึกว่ามันเป็นวัตถุที่ทำซ้ำได้)

อ่านเพิ่มเติม. http://www.lepus.org.uk/ref/companion/Iterator.xml


6
วัตถุที่ไม่ใช่คอลเลกชันไม่สามารถทำซ้ำได้ไม่เป็นความจริงโดยทั่วไป เพื่อให้ตัวอย่างเพียงไม่กี่ตัวกำเนิดจะทำซ้ำได้ แต่ไม่ใช่คอลเลกชันและวัตถุตัววนซ้ำที่สร้างขึ้นโดยการเรียกiter()ใช้คอลเลกชันมาตรฐานนั้นสามารถทำซ้ำได้ แต่ไม่ใช่ตัวสะสมเอง
Mark Amery
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.