typing/Generic __orig_class__ availability during __init__ in 3.6 vs 3.7
baltus-atomicrules opened this issue · 9 comments
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
Yes, this is unfortunate, but as you know, this is undocumented internal attribute that you are using totally at your own risk. So unless you have a simple idea how to fix this, I don't think there is anything we can do here.
@baltus-atomicrules
For the record, you can use pytypes.get_orig_class to solve this.
Note: It's only available in master as of this writing. (I hope to make an new release soon.)
this is undocumented internal attribute that you are using totally at your own risk.
Sure, but that makes also typing_inspect fail inside constructor: ilevkivskyi/typing_inspect#35
We can't change what typing looks like in 3.6 or 3.7, so I don't think there's anything actionable in this issue.
I mean, the same still holds true in 3.8, 3.9, 3.10. So the issue in all of those that inside __init__
you cannot access __orig_class__
. The issue was only reported when 3.7 was out, but it is still valid.
This has been annoying me as of late, couldn't we just have it not be available in __new__
but available in __init__
?
Hi, is there any updates? Thanks
I still face this issue with Python 3.11. Are there any valid workarounds for this?
Please report any issues related to issues with the typing
module to CPython's issue tracker: https://github.com/python/cpython/issues, where the module is maintained nowadays.