typing/Generic orig_class availability during init in 3.6 vs 3.7 · Issue #658 · python/typing (original) (raw)
I observe that when executing __init__ in a Generic class, the value of __orig_class__ is available in version 3.6 but not in 3.7
(I am comparing 3.6.7 with 3.7.0)
I've attached a simple example that defines a Generic class and then accesses __orig_class__ in the associated __init__ method.
N = TypeVar('N')
class ZZ(Generic[N]):
def __init__(self):
print("__orig_class__ is: ", self.__orig_class__)
In 3.6, this code runs fine:
In [42]: import Simple
In [51]: a = Simple.ZZ[int]
In [56]: b = a()
__orig_class__ is: Simple.ZZ[int]
In 3.7 however, the value of __orig_class__ is not available:
In [4]: import Simple
In [5]: a = Simple.ZZ[int]
In [6]: b = a()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-6-52a6c422c17e> in <module>
----> 1 b = a()
/tool/pandora64/.package/python-3.7.0/lib/python3.7/typing.py in __call__(self, *args, **kwargs)
668 raise TypeError(f"Type {self._name} cannot be instantiated; "
669 f"use {self._name.lower()}() instead")
--> 670 result = self.__origin__(*args, **kwargs)
671 try:
672 result.__orig_class__ = self
/proj/emu_scratch4/users/dbaltus/python/experiment/Simple.py in __init__(self)
4 class ZZ(Generic[N]):
5 def __init__(self):
----> 6 print("__orig_class__ is: ", self.__orig_class__)
AttributeError: 'ZZ' object has no attribute '__orig_class__'
> /proj/emu_scratch4/users/dbaltus/python/experiment/Simple.py(6)__init__()
2
3 N = TypeVar('N')
4 class ZZ(Generic[N]):
5 def __init__(self):
----> 6 print("__orig_class__ is: ", self.__orig_class__)
ipdb> q
This occurs because in 3.7, the __call__ method of _GenericAlias does not set the value of __orig_class__ until after __init__ is called. (It is done differently in 3.6).
def __call__(self, *args, **kwargs):
if not self._inst:
raise TypeError(f"Type {self._name} cannot be instantiated; "
f"use {self._name.lower()}() instead")
result = self.__origin__(*args, **kwargs)
try:
result.__orig_class__ = self
except AttributeError:
pass
return result