Python Forum
Trying to understand how isinstance(values, collections.Iterable) work.
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Trying to understand how isinstance(values, collections.Iterable) work.
#1
A text book is demonstrating how the built in sum function can be implemented with error checking. Here are the first 2 lines,

def sum(values):
    if not isinstance(values, collections.Iterable):
    # There is more, but I am guessing it's not relavent for the question
I understand that with isinstance() method we are testing if values variable are of a certain class type. My first guess is, Iterable is a class available in collections module, and I tried to verify that by following the definition.

I tried to find the definition of collections.Iterable by ctrl+clicking on it on PyCharm. The IDE took me to the following section of code located in <python_env>\Lib\typing.py,

# Various ABCs mimicking those in collections.abc.
_alias = _SpecialGenericAlias

Hashable = _alias(collections.abc.Hashable, 0)  # Not generic.
Awaitable = _alias(collections.abc.Awaitable, 1)
Coroutine = _alias(collections.abc.Coroutine, 3)
AsyncIterable = _alias(collections.abc.AsyncIterable, 1)
AsyncIterator = _alias(collections.abc.AsyncIterator, 1)
Iterable = _alias(collections.abc.Iterable, 1) # Takes me here
Iterator = _alias(collections.abc.Iterator, 1)
Reversible = _alias(collections.abc.Reversible, 1)
Sized = _alias(collections.abc.Sized, 0)  # Not generic.
Container = _alias(collections.abc.Container, 1)
Collection = _alias(collections.abc.Collection, 1)
Callable = _CallableType(collections.abc.Callable, 2)
Callable.__doc__ = \
I am under the assumption that _alias is a function, but ctrl+clicking it take me to _SpecialGenericAlias class's cosntructor.

At this point I am confused what is going on with the following code,
isinstance(values, collections.Iterable):
collections.Iterable seems to be a static variable of some sort in Typing module. But I was expecting a class name as a second argument in the isinstance method.

Right after the code, the book says the following, "The abstract base class, collections.Iterable, includes all of Python’s iterable containers types that guarantee support for the for-loop syntax..". I guess I am looking for the declaration of collections.Iterable class.
Reply
#2
Originally, isinstance() only tested if a variable has a certain class type, but when abstract base classes where introduced in PEP 3119, this semantic was extended and isinstance now also test if the type of a variable has been declared as implementing a certain abstract base class, more or less in the way that interfaces work in Java. The collections module defines a certain number of abstract base classes such as 'Iterable'. In fact, isinstance(obj, collections.abc.Iterable) will return True if this abstract class is in the ancestor types of obj's type, or if one of the ancestor types of obj's type has been registered as implementing this abstract base class (without necessarily being a subclass of it). Any class that has an __iter__() method can be declared as such.
Reply
#3
This stuff has moved around. collections.Iterable is a deprecated location for what is now collections.abc.Iterable.

Through the redirects left in collections (see collections/__init__.py and collections/abc.py, collections.Iterable is in fact a class.

Output:
$ python3 -c "import collections; print(str(collections.Iterable))" <string>:1: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.10 it will stop working <class 'collections.abc.Iterable'>
Gribouillis likes this post
Reply
#4
> in fact, isinstance(obj, collections.Iterable) will return True if this abstract class is in the ancestor types of obj's type, or if one of the ancestor types of obj's type has been registered as implementing this abstract base class (without necessarily be a subclass of it). Any class that has an __iter__() method can be declared as such.

Could you please elaborate on this.

Here is my interpretation: If obj or any of it's parent implements __iter__() method, isinstance(obj, collections.Iterable) will return true. For example, str class implements __iter__(), therefore

x = str('test')
isinstance(x, collections.abc.Iterable) # returns true
By registering - do you mean just implementation the __iter__() method?
Reply
#5
For normal abstract classes, it is necessary to call a register() function to register a class, as described in the abc module. However, when the abstract class defines a __subclasshook__() method, a dynamic check can take place and registering is not necessary. This seems to be the case of collections.abc.Iterable and it means that an __iter__() method suffices. For example
>>> class A:
...     def __iter__(self):
...         return iter(())
... 
>>> import collections.abc
>>> isinstance(A(), collections.abc.Iterable)
True
quazirfan likes this post
Reply
#6
Some other perceive/ways to solve it,one with EAFP and one hypermodern way.
s = 'hello'
try:
    iter(s)
    print('A iterable')
except TypeError:
    print('Not iterable')
Output:
A iterable
From "Fluent Python" by Luciano Ramalho:
Quote:As of Python 3.4, the most accurate way to check whether an object x is iterable is to call iter(x) and handle a TypeError exception if it isn’t.
This is more accurate than using isinstance(x, abc.Iterable), because iter(x) also considers the legacy getitem method, while the Iterable ABC does not.
So a hypermodern one that i think is cool,i while go i discovered strongtyping.
So it make type hint actually do something at runtime,do not need eg mypy
from typing import Iterable
from strongtyping.strong_typing import match_typing

@match_typing
def func(seq: Iterable[int]) -> list[str]:
    return [str(i) for i in seg]

print(func([1, 2, 3]))
Output:
['1', '2', '3']
It easy to see that argument most be Iterable and of type int.
Fail on with TypeMisMatch on:
['1', 2, 3]
'hello'
'456'
999
Work again with.
print(func(range(1, 5))) 
Output:
['1', '2', '3', '4']
So it could make isinstance and try/except not needed.
Doc Wrote:Without strongtyping you have to check for every valid type of every parameter in every function,
which creates a lot of noisy/bloated code and begs the questions "Why use Python type hinting at all?":
Reply
#7
I don't see what is so modern with the idea of checking the arguments type at runtime. It looks like an extreme regression to me. Duck typing is what made Python successful. Otherwise we can use a statically typed language. It will have better performance.
Reply
#8
(Aug-10-2021, 06:46 AM)Gribouillis Wrote: I don't see what is so modern with the idea of checking the arguments type at runtime. It looks like an extreme regression to me. Duck typing is what made Python successful. Otherwise we can use a statically typed language. It will have better performance.
Yes i do agree,have not used type hint so much myself and that strongtyping do check at runtime is kind of interesting (maybe useful in some cases).
Lager companies that use Python so is now type annotations heavily used.
Our journey to type checking 4 million lines of Python

I did not like type annotations much at first,but i see that in some cases that it can help readability and documentation of code
In newer Python version eg 3.9 they clean it more up PEP 585.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Question how to solve `'TypeError: 'int' object is not iterable`? netanelst 2 1,579 May-24-2022, 12:03 PM
Last Post: deanhystad
  cs.collections error DaveG 7 1,759 Apr-06-2022, 04:18 PM
Last Post: Larz60+
  basic question isinstance tames 5 2,845 Nov-23-2020, 07:20 AM
Last Post: tames
  Cannot unpack non-iterable NoneType object, i would like to ask for help on this. Jadiac 3 8,934 Oct-18-2020, 02:11 PM
Last Post: Jadiac
  subprogram issues: cannot unpack non-iterable function object error djwilson0495 13 6,017 Aug-20-2020, 05:53 PM
Last Post: deanhystad
  Help with isinstance command (very simple code) Laplace12 2 2,014 Jul-30-2020, 05:26 AM
Last Post: Laplace12
  isinstance() always return true for object type check Yoki91 2 2,579 Jul-22-2020, 06:52 PM
Last Post: Yoki91
  AttributeError: 'collections.OrderedDict' object has no attribute 'value_counts Kristenl2784 4 7,361 Jul-17-2020, 01:50 AM
Last Post: palladium
  collections.OrderedDict Bert123456 2 1,784 Jul-09-2020, 08:51 PM
Last Post: Bert123456
  Why the result of "extended iterable unpacking" with set() is unpredictable? zohanlin 2 2,081 Jun-29-2020, 10:30 AM
Last Post: zohanlin

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020