Reputation: 10483
How can one check a complete type signature of a nested abstract class? In this example
In [4]: from typing import Sequence
In [5]: IntSeq = Sequence[int]
In [6]: isinstance([1], IntSeq)
Out[6]: True
In [7]: isinstance([1.0], IntSeq)
Out[7]: True
I want the last isinstance
call to actually return False
, while it only checks that the argument is a Sequence
. I thought about recursively checking the types, but IntSeq
has no public attributes that store the nested type(s):
In [8]: dir(IntSeq)
Out[8]:
['__abstractmethods__',
'__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__extra__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__len__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__origin__',
'__parameters__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__slots__',
'__str__',
'__subclasshook__',
'__weakref__',
'_abc_cache',
'_abc_negative_cache',
'_abc_negative_cache_version',
'_abc_registry']
So it doesn't seem to be straightforward to get nested types. I can't find relevant information in the docs.
P.S. I need this for a multiple dispatch implementation.
Update
Thanks to the feedback from Alexander Huszagh and Blender we now know that abstract classes in Python 3.5 (might) have two attributes that store the nested types: __parameters__
and __args__
. The former is there under both Linux (Ubuntu) and Darwin (OS X), though it is empty in case of Linux. The later is only available under Linux and stores the types like __parameters__
does under OS X. This implementation details add up to the confusion.
Upvotes: 4
Views: 1009
Reputation: 160357
I see you're trying to implement something using a module that is still provisional; you're bound to encounter a changing interface if you do this.
Blender noticed that the __parameters__
argument holds the parameters to the type; this was true until, I believe 3.5.1
. In my git clone of the most recent version of Python (3.6.0a4+
) __parameters__
again holds an empty tuple, __args__
holds the argument and __origin__
is the first entry in its __bases__
attribute:
>>> intSeq = typing.Sequence[int]
>>> intSeq.__args__
(<class 'int'>,)
>>> intSeq.__parameters__
()
>>> intSeq.__origin__
typing.Sequence<+T_co>
Since 3.6
is when typing will, from what I understand from PEP 411
, leave provisional and enter a stable state, this is the version you should be working with to implement your functionality.
Upvotes: 2