2015-11-27 19 views
6

Đây là mã của tôi:Tại sao một đối tượng có thể lặp lại không phải là một trình lặp?

from collections import deque 

class linehistory: 
    def __init__(self, lines, histlen=3): 
     self.lines = lines 
     self.history = deque(maxlen=histlen) 

    def __iter__(self): 
     for lineno, line in enumerate(self.lines,1): 
      self.history.append((lineno, line)) 
      yield line 

    def clear(self): 
     self.history.clear() 


f = open('somefile.txt') 
lines = linehistory(f) 
next(lines) 

Lỗi:

Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
    TypeError: 'linehistory' object is not an iterator 

Tôi không có ý tưởng tại sao các đối tượng linehistory không phải là một iterator vì nó đã bao gồm __iter__ phương pháp trong the lớp.

+2

Bạn cũng cần phải xác định một 'tiếp theo() 'phương pháp (hoặc '__next __()' cho Python 3). – xyres

+0

Thiếu phương thức '__next__': http://pymbook.readthedocs.org/en/latest/igd.html#iterators – schwobaseggl

+6

Phương thức' __iter__' làm cho đối tượng của bạn trở thành [iterable] (https://docs.python.org/ 3.5/library/collections.abc.html # collections.abc.Iterable), trong khi phương thức '__next__' biến nó thành một [iterator] (https://docs.python.org/3.5/library/collections.abc.html# collections.abc.Iterator). Sử dụng 'lines = iter (linehistory (f))' và bạn sẽ ổn. – Vincent

Trả lời

3

đối tượng Iterator cần một phương pháp __iter__ nhưng họ cũng cần phải có next thực hiện:

The iterator objects themselves are required to support the following two methods, which together form the iterator protocol:

iterator.__iter__()
Return the iterator object itself.

iterator.next()
Return the next item from the container.

Python 2.7 Source

Trong Python 3.x đây là những tên hàm:

iterator.__iter__()

iterator.__next__()

Python 3.x Source

0

Như đã nêu trong các chú thích và câu trả lời khác, bạn cũng cần xác định phương thức next() trong lớp của bạn để biến nó trở thành một trình lặp.

Ngoài ra, tôi nhận thấy bạn đang sử dụng yield thay vì return. Do đó, việc thực hiện next(lines) sẽ không in dòng tiếp theo nhưng nó sẽ cung cấp cho bạn đối tượng trình tạo.

class linehistory: 
    def __init__(self, lines, histlen=3): 
     self.lines = lines 
     self.history = deque(maxlen=histlen) 

    def __iter__(self): 
     return self 

    def clear(self): 
     self.history.clear() 

    def next(self): # Python 3: __next__(self) 
     for lineno, line in enumerate(self.lines,1): 
      self.history.append((lineno, line)) 
      return line 
     else: 
      raise StopIteration 

Và sau đó làm như thế này:

>>> f = open("somefile.txt") 
>>> lines = linehistory(f) 
>>> next(lines) 
... "Some line" 

Nếu bạn sử dụng yield thay vì return, nó sẽ cho một đối tượng phát:

>>> = open("somefile.txt") 
>>> lines = linehistory(f) 
>>> next(lines) 
... <generator object next at 0xb4bb961c> 
>>> # To print the line you'll have to do: 
>>> next(next(lines)) 
... "Some line" 
7

Nói tóm lại, "iterable" là đối tượng tôi muốn lặp lại. Nó có __iter__().

Tuy nhiên, "trình lặp" là đối tượng được sử dụng để lặp lại. Nó có next() hoặc __next__(). Vì bất kỳ trình lặp nào cũng có thể lặp lại (là trình lặp của riêng nó), nó cũng có __iter__().

Bạn có thể nhận được trình lặp cho bất kỳ lần lặp nào có iter(obj).

Trong ví dụ của bạn, linehistory (phải viết là LineHistory) có thể lặp lại vì nó có số .__iter__(). Đối tượng máy phát được tạo ra với điều này là một trình lặp (như mọi đối tượng máy phát).

3

I have no idea why the linehistory object is not an iterator since it has already included __iter__ method in the class.

Sai. Xem Iterator Types:

The iterator objects themselves are required to support the following two methods, which together form the iterator protocol:

iterator.__iter__()
Return the iterator object itself. This is required to allow both containers and iterators to be used with the for and in statements. This method corresponds to the tp_iter slot of the type structure for Python objects in the Python/C API.

iterator.__next__()
Return the next item from the container. If there are no further items, raise the StopIteration exception. This method corresponds to the tp_iternext slot of the type structure for Python objects in the Python/C API.

Tuy nhiên bạn có thể duyệt qua lines, đó là bởi vì phương pháp __iter__ của bạn là một chức năng máy phát điện, xem Generator Types:

Python’s generators provide a convenient way to implement the iterator protocol. If a container object’s __iter__() method is implemented as a generator, it will automatically return an iterator object (technically, a generator object) supplying the __iter__() and __next__() methods. More information about generators can be found in the documentation for the yield expression.

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