Sorry for questioning here... If there is a better place will be grateful for pointing to :)
I'm looking for code-saving algorithm of construction generics. And, explored typing module a bit, came to the solution, workes for me:
import typing as ty
T = ty.TypeVar('T')
class A(ty.Generic[T]):
# __args are unique every instantiation
__args: ty.Optional[ty.Tuple[ty.Type[T]]] = None
value: T
def __init__(self, value: ty.Optional[T]=None) -> None:
"""Get actual type of generic and initizalize it's value."""
cls = ty.cast(A, self.__class__)
if cls.__args:
self.ref = cls.__args[0]
else:
self.ref = type(value)
if value:
self.value = value
else:
self.value = self.ref()
cls.__args = None
def __class_getitem__(cls, *args: type) -> ty.Type['A']:
"""Recive type args, if passed any before initialization."""
cls.__args = ty.cast(ty.Tuple[ty.Type[T]], args)
return super().__class_getitem__(*args, **kwargs) # type: ignore
a = A[int]()
b = A(int())
c = A[str]()
print([a.value, b.value, c.value]) # [0, 0, '']
How dangerous to use this internal interpretation of typing public API?
What exactly do you want to achieve? Do you want to access type argument of the original class on an instance? For this you can use obj.__orig_class__.__args__:
>>> class A(Generic[T]): ...
...
>>> A[int]().__orig_class__.__args__
(<class 'int'>,)
How dangerous to use this internal interpretation of typing public API?
Exactly the same amount of danger as while using other private Python APIs -- they can change without notice at any moment.
Also _questions_ (not bug reports or feature requests) are better discussed in the typing Gitter channel.
But obj.__orig_class__ is appeared after object construction and initialization, and after all it's bases and metaclasses initialization)
What exactly do you want to achieve?
real-time duck-typing for users didn't bother by static one))
P.S. Also, it can be useful for some fabrics
>>> class A(Generic[T]):
... def __init__(self):
... self.value = self.__orig_class__.__args__[0]()
...
>>>
>>> A[int]().value
0
Anyway, you can use whatever way. Maybe __class_getitem__ is even slightly better, at least __class_getitem__ is a documented special method (although its behavior for generics is not).
ehhm...
Traceback (most recent call last):
File "E:\packages\pyksp\pyksp\simple_test.py", line 64, in <module>
A[int]().value
File "C:\Users\Levitanus\AppData\Local\Programs\Python\Python37-32\lib\typing.py", line 670, in __call__
result = self.__origin__(*args, **kwargs)
File "E:\packages\pyksp\pyksp\simple_test.py", line 61, in __init__
self.value = self.__orig_class__.__args__[0]()
AttributeError: 'A' object has no attribute '__orig_class__'
You see, this is how dangerous using internal APIs (also your example crashes as well in Python 3.6 and older).