«имя 'T' не определено» при оценке аннотаций для унаследованных методов с использованием синтаксиса параметров типа PythPython

Программы на Python
Ответить
Anonymous
 «имя 'T' не определено» при оценке аннотаций для унаследованных методов с использованием синтаксиса параметров типа Pyth

Сообщение Anonymous »

Я обновляю кодовую базу до Python 3.12 и переношу наши универсальные классы для использования нового синтаксиса PEP 695, например:

Код: Выделить всё

class Box[T]:
...
вместо:

Код: Выделить всё

T = TypeVar('T')
class Box(Generic[T]):
...
Большая часть из них работает, но я столкнулся с ошибкой NameError при попытке динамической проверки подсказок типа в методе подкласса, если этот метод был обернут пользовательским декоратором в родительском классе:

Код: Выделить всё

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)
При запуске приведенного выше кода логика времени выполнения выполняется отлично, но typing.get_type_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 основан на непосредственной проверке атрибутов функции-оболочки.
Почему Python не может найти T здесь? Он явно знает, что такое T во время выполнения. Это ошибка в реализации PEP 695 в Python 3.12, или я в корне не понимаю, как работают новые универсальные области видимости?
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»