Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Protocols cannot be used with isinstance()" - why not?

The new typing module contains several objects with names like "SupportsInt" (-Float, -Bytes, etc.). The name, and the descriptions on the documentation page for the module, might be read to suggest that you can test whether an object is of a type that "supports __int__()". But if you try to use isinstance(), it gives a response that makes it clear that that isn't something you are meant to do:

>>> isinstance(5, typing.SupportsInt)
(Traceback omitted)
TypeError: Protocols cannot be used with isinstance().

On the other hand, you can use issubclass():

>>> issubclass((5).__class__, typing.SupportsInt)
True
>>> issubclass(type(5), typing.SupportsInt)
True

What is a "protocol" in this context? Why does it disallow the use of isinstance() in this way?

like image 655
Hammerite Avatar asked Jan 17 '16 22:01

Hammerite


People also ask

How does Python define Isinstance?

Definition and Usage The isinstance() function returns True if the specified object is of the specified type, otherwise False . If the type parameter is a tuple, this function will return True if the object is one of the types in the tuple.

Is Isinstance fast?

The isinstance() function is faster than the type function. We can compare both their performance by using the timeit library. As you can see, the isinstance() function is 30 times faster than type() function.


1 Answers

This is all of the reasoning given in PEP 484, the PEP for the typing module:

Because typing.Callable does double-duty as a replacement for collections.abc.Callable , isinstance(x, typing.Callable) is implemented by deferring to `isinstance(x, collections.abc.Callable) . However, isinstance(x, typing.Callable[...]) is not supported.

A protocol is also known as a magic method. These are most of the python protocols (full list here):

>>> dir(object)
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', 
'__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__setattr__', '__sizeof__', '__str__', '__subclasshook__']

I have not found any clear reason for why typing does not support isinstance. The reason that issubclass works is that isinstance uses the __class_ protocol which is not allowed in typing, while issubclass uses the __subclasshook__ protocol which is allowed. I believe the reason is that the functionality was already coded in collections.abc.Callable and they did not want to recode it in the typing module.

like image 145
rassar Avatar answered Oct 13 '22 16:10

rassar