On Fri, Aug 14, 2020 at 10:43:31AM +0200, Marco Sulla wrote:
> Many times I want a function parameter that is an iterable but not a
> string. Usually I do:
>
> try:
> var.__iter__
> except AttributeError:
> # not an iterable
> else:
> try:
> var.isascii
> except AttributeError:
> # put yuour code here
That's buggy. Your test for `var.__iter__` has false positives and false
negatives:
False positives: if an *instance* (but not the class) happens to have an
attribute called `__iter__` your test will think it is iterable when it
is not.
py> class Demo:
... pass
...
py> obj = Demo()
py> obj.__iter__ = lambda: iter('abc')
py> iter(obj)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'Demo' object is not iterable
Remember that dunder methods are only called on the class, not on the
instance.
False negatives: if your class is indexable and obeys the sequence
iteration protocol, then it is iterable, but your test will think it is
not:
py> class Demo:
... def __getitem__(self, i):
... if i > 5: raise IndexError
... return i**2
...
py> list(Demo())
[0, 1, 4, 9, 16, 25]
The best and most reliable way to check if something is iterable is to
ask iter:
try:
iter(obj)
except TypeError:
# not iterable
Alas, the Iterable abc does not recognise the sequence iteration
protocol, so `isinstance(obj, Iterable)` fails too.
Your test for stringness is also buggy: you have no guarantee that an
object with an "isascii" attribute is a string. It will give a false
positive to any object with an attribute of that name, even if it isn't
a method.
Why not just test for `isinstance(obj, str)`?
(Does anyone care about UserStr?)
--
Steven
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/HXHJDIJTUTKJIZK2SYQDVE3G5VFCOJ23/
Code of Conduct: http://python.org/psf/codeofconduct/