Код: Выделить всё
class Box[T]:
...
Код: Выделить всё
T = TypeVar('T')
class Box(Generic[T]):
...
Код: Выделить всё
from functools import wraps
import typing
# A standard route/event tracking decorator that preserves annotations
def track_event(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
# We explicitly sync annotations for an external API generator tool
wrapper.__annotations__ = func.__annotations__
return wrapper
# Parent generic class using Python 3.12+ syntax
class BaseService[T]:
@track_event
def process(self, data: T) -> str:
return f"Processed: {str(data)}"
# Subclass specifying the concrete type
class StringService(BaseService[str]):
pass
# Driving code that triggers the error
if __name__ == "__main__":
service = StringService()
print(service.process("hello")) # This works perfectly fine at runtime!
# This blows up:
hints = typing.get_type_hints(StringService.process)
print(hints)
Код: Выделить всё
Traceback (most recent call last):
File "main.py", line 29, in
hints = typing.get_type_hints(StringService.process)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/typing.py", line 1944, in get_type_hints
value = _eval_type(value, globalns, localns)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/typing.py", line 390, in _eval_type
return arg._evaluate(globalns, localns, recursive_guard)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/typing.py", line 837, in _evaluate
eval(self.__forward_code__, globalns, localns),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "", line 1, in
NameError: name 'T' is not defined
- Если я удалю декоратор @track_event, typing.get_type_hints разрешится правильно.
- Если я вернусь к старому синтаксису Python 3.11 T = TypeVar('T'), код будет работать даже с декоратор.
- Я копирую аннотации через оболочку.__annotations__ = func.__annotations__, поскольку наш инструмент создания документации/API основан на непосредственной проверке атрибутов функции-оболочки.
Мобильная версия