Требовать, чтобы декорированная функция принимала аргумент, соответствующий привязке TypeVar, без сужения до этого типа.Python

Программы на Python
Ответить Пред. темаСлед. тема
Гость
 Требовать, чтобы декорированная функция принимала аргумент, соответствующий привязке TypeVar, без сужения до этого типа.

Сообщение Гость »

Если я определю свой декоратор следующим образом

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

T = TypeVar('T', bound=Event)

def register1(evtype: Type[T]) -> Callable[[Callable[[T], None]], Callable[[T], None]]:
def decorator(handler):
# register handler for event type
return handler
return decorator
Я получаю правильную ошибку, если использую ее для неправильной функции:

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

class A(Event):
pass

class B(Event):
pass

@register1(A) # Argument of type "(ev: B) -> None" cannot be assigned to parameter of type "(A) -> None"
def handler1_1(ev: B):
pass
Однако это не сработает, если я применю декоратор несколько раз:

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

@register1(A) # Argument of type "(B) -> None" cannot be assigned to parameter of type "(A) -> None"
@register1(B)
def handler1_3(ev: A|B):
pass
Я как бы хочу, чтобы декораторы создали объединение разрешенных/обязательных типов аргументов.
Я думаю, ParamSpec это способ решить эту проблему, но как я могу использовать ParamSpec, чтобы не перезаписывать тип аргумента, но также требовать, чтобы тип аргумента соответствовал типу, указанному в аргументе декоратора?
Использование ParamSpec не приводит к какой-либо ошибке типа:

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

P = ParamSpec("P")

def register2(evtype: Type[T]) -> Callable[[Callable[P, None]], Callable[P, None]]:
def decorator(handler):
# ...
return handler
return decorator

@register2(A) # This should be an error
def handler2_1(ev: B):
pass
Если я добавлю еще одну переменную TypeVar и использую Union, это будет работать для функций с двойным и даже тройным декорированием, но не для функций с одинарным декорированием.< /p>

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

T2 = TypeVar('T2')

def register3(evtype: Type[T]) -> Callable[[Callable[[Union[T,T2]], None]], Callable[[Union[T,T2]], None]]:
def decorator(handler):
# ...
return handler
return decorator

# Expected error:
@register3(A) # Argument of type "(ev: B) -> None" cannot be assigned to parameter of type "(A | T2@register3) -> None"
def handler3_1(ev: B):
pass

# Wrong error:
@register3(A) # Argument of type "(ev: A) -> None" cannot be assigned to parameter of type "(A | T2@register3) -> None"
def handler3_2(ev: A):
pass

# Works fine
@register3(A)
@register3(B)
def handler3_3(ev: A|B):
pass
Во время написания этого вопроса я подходил к решению все ближе и ближе.
И я представлю свое собственное решение в ответе.
Однако мне интересно, есть ли лучшие способы решить эту проблему.

Подробнее здесь: https://stackoverflow.com/questions/781 ... -without-n
Реклама
Ответить Пред. темаСлед. тема

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

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

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

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

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

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