As title. I mean, you can invoke
next(obj) and point to the next element. So the internal state of the iterable or generator will change.
Why they are hashable?
While the internal state of the generator can change, the generator as a whole can never add something to itself, and can never go back a step while iterating over it. Therefore, a generator is a fixed immutable object, which is almost the definition of being hashable.
But even more deeply than that, even mutable objects can be hashable as long as they define
__hash__ as an instance method, but that is rarely desireable for mutable objects.
The general rule for hashing objects is:
__eq__ is overridden, object equality is defined by identity, and hashing matches
__eq__ is overridden, and
__hash__ is not, then hashing is blocked by default (because mutability that affects the result of an equality check would break the hash invariants); re-enabling hashing requires implementing
__hash__, which implicitly says "My equality and hash semantics are stable/consistent over time", but doesn’t require that things not tied to equality or the hash code be stable.
Point is, the condition for hashability isn’t full immutability, it’s consistency with equality (and implied stability of both equality and hash). Since most iterators and all generators don’t implement
__eq__ (there is no meaningful way to implement it without running out the iterator and losing the information you just used to compare it), it’s all based on identity, just like with any user-defined object that doesn’t define equality.