Detection of an object repeatedly repeating

Does obj == iter(obj) have obj not repeated repeatedly and vice versa? I have not seen such a wording in the documents, but according to this comment, the standard library checks to see if an object is repeated repeatedly by testing if iter(obj) is obj :

@agf: there are parts of the Python standard library that rely on this part of the specification; they detect if something is an iterator / generator by testing if iter(obj) is obj: because the true iterator / generator object will have __iter__ defined as an identification function. If the test is correct, they are converted to list to repeat the repetition, otherwise he suggested that the object is iterable and they can use it as is.
- ShadowRanger June 3 at 17:23

The docs indicate that if obj is an iterator, this requires iter(obj) return obj . But I do not think that it is enough to conclude that non-repeating repeating objects can be identified with iter(obj) is obj .

+7
python iterator
source share
1 answer

All iterators are iterable, but not all iterations are iterators.

The only requirement for iteration is that it defines the __iter__() method, which returns an iterator:

For container objects, one method must be defined in order to support iteration:

container.__iter__()
Return the iterator object.

an iterator must follow an iterator protocol that has two requirements:

  • It has a __iter__() method that returns the object itself :

    iterator.__iter__()
    Return the iterator object itself.

  • It has a __next__() method, which returns the next element for each call and, after exhaustion, raises the StopIteration on each subsequent call :

    As soon as the __next__() iterator method raises StopIteration , it should continue to do so on subsequent calls. Implementations that do not obey this property are considered violated.

These requirements mean that iterators never repeat and that you can always confirm that an iterable is an iterator (and therefore unique by definition), confirming that iter(obj) is obj is True :

 def is_unrepeatable(obj): return iter(obj) is obj 

However: since the only requirement for iterable is that iter(obj) returns some iterator, you cannot prove that it repeats. The iterable can define the __iter__() method, which returns an iterator with different behavior each time it calls: for example, it can return an iterator that iterates over its elements on the first call, but on subsequent calls returns an iterator that immediately raises StopIteration .

Such behavior would be strange (and annoying), but not forbidden. Here is an example of a non-repeatable iterative class that is not an iterator:

 class Unrepeatable: def __init__(self, iterable): self.iterable = iterable self.exhausted = False def __iter__(self): if self.exhausted: return else: self.exhausted = True yield from self.iterable 

 >>> x = Unrepeatable([1,2,3]) >>> list(x) [1, 2, 3] >>> list(x) [] >>> iter(x) is x False >>> 

I would not hesitate to call such a “fake iterator” misbehaving, and I cannot think of a situation when you find it in the wild, but, as shown above, this is possible.

+5
source share

All Articles