I came across the following (using Python 3.8.3):
from collections.abc import Iterable
from weakref import proxy
class Dummy:
pass
isinstance(d := Dummy, Iterable)
# False (as expected)
isinstance(p := proxy(d), Iterable)
# True (why?!)
for _ in p:
# raises TypeError
pass
How could the proxy object pass the iterable-test?
It provides __iter__
in case the underlying type provides it. __iter__
must be implemented on the type to work, not the instance, so it can't conditionally define __iter__
without fragmenting into many different classes, not just a single proxy
class.
Unfortunately, the Iterable
test just checks if the class defines __iter__
, not whether it works, and proxy
doesn't know if it really works without calling the wrapped class's __iter__
. If you want to check for iterability, just iterate it, and catch the TypeError
if it fails. If you can't iterate it immediately, while it's subject to time-of-check/time-of-use race conditions, you could write your own simple tester that covers whether it can actually be iterated:
def is_iterable(maybeiter):
try:
iter(maybeiter)
except TypeError:
return False
else:
return True