Ввод свойства объекта функцииPython

Программы на Python
Anonymous
Ввод свойства объекта функции

Сообщение Anonymous »

Мне нужно реализовать протокол, который отправляет сообщение и в свою очередь получает ответ. Обычно ответ происходит мгновенно, но в некоторых случаях сообщение переводит устройство в правильное состояние для обработки других сообщений, и только после обработки других сообщений устройство ответит на исходное сообщение, устанавливающее состояние.
Поскольку фактический код генерации сообщения на основе параметров и построения объекта ответа довольно повторяется, я использую для этого декоратор. Хотя в 90% случаев пользователь хочет отправитьMessageX() -> ResponseToMessageX, бывают случаи, когда пользователю приходится отправлятьMessageX() -> Future. Поскольку обе функции принимают одни и те же параметры и по сути возвращают одно и то же (

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

ResponsToMessageX
, по крайней мере, после разрешения будущего), имеет смысл сгенерировать обе функции из декоратора.
Самый простой способ сделать это для меня - злоупотреблять питонами, все есть объект и просто добавьте вторую функцию как свойство к объекту функции, т.е.:

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

def decorator(f):
def decorated_f():
return f()

def decorated_f_split():
return f'()

decorated_f.second_function = decorated_f_split

return decorated_f
(Если я могу помочь, я стараюсь избегать метаклассов, чтобы упростить задачу и избежать ограничений).
Чтобы упростить работу пользователя Мне бы хотелось, чтобы подсказки по-прежнему работали (чтобы редактор мог подсказывать, какие свойства имеет объект ответа).
Хотя я заставил это работать, пирайт все еще жалуется, и я не могу избавиться от предупреждения. Вот MWE того, что я придумал:

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

from functools import wraps
from typing import (
Any,
Awaitable,
Callable,
Concatenate,
ParamSpec,
Protocol,
TypeVar,
cast,
)

T = TypeVar("T")
C = TypeVar("C", covariant=True)
P = ParamSpec("P")  # , covariant=True)

class X(Protocol[P, C]):
def split(self, *args: Any, **kwds: Any) -> Awaitable[C]:
...

def __call__(self, *args: Any, **kwds: Any) -> C:
...

def wrap_returntype_awaitable(f: Callable[P, T]) -> Callable[P, Awaitable[T]]:
f.__annotations__["return"] = Awaitable[T]

g = cast(Callable[P, Awaitable[T]], f)
return g

def decorator(f: Callable[Concatenate[Any, P], C]) -> X[P, C]:
class Wrapper:
# @wrap_returntype_awaitable
@wraps(wrap_returntype_awaitable(f))
async def split(self, *args: P.args, **kwds: P.kwargs) -> Awaitable[C]:
await self.send_command()
return self.get_response()

@wraps(f)
async def __call__(self, *args: P.args, **kwds: P.kwargs) -> C:
response_receiver = await Wrapper.split(self, *args, **kwds)
return await response_receiver

Wrapper.split.__annotations__["return"] = Awaitable[C]

return Wrapper()

class A:
async def send_command(self):
pass

async def get_response(self):
pass

async def command(self, a: int) -> int:
await self.send_command()
return a

@decorator
async def x(self, a1: int) -> int:
...

async def demo():
a = A()

response = await a.x()
split_command = await a.x.split()
split_response = await split_command
Я чувствую себя вынужденным использовать класс внутри декоратора, поскольку в противном случае я не могу сообщить Pytright, что я хочу присвоить свойство функции (я не уверен, как сообщить Pytright, что объект, который я возвращаю, имеет разделение свойств, которое мне нужно установить (кроме подавления предупреждений о типе в этой строке)). Проблема заключается в сопоставлении типа self, в частности, поскольку я обычно наследую send_command/

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

get_response
сообщение базового типа класса A (опущено для упрощения MWE).
Pyright жалуется на следующее:

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

p2.py:38:24 - error: Cannot access member "send_command" for type "Wrapper"
Member "send_command" is unknown (reportGeneralTypeIssues)
p2.py:39:25 - error: Cannot access member "get_response" for type "Wrapper"
Member "get_response" is unknown (reportGeneralTypeIssues)
p2.py:48:12 - error: Expression of type "Wrapper" cannot be assigned to return type "X[P@decorator, C@decorator]"
"Wrapper" is incompatible with protocol "X[P@decorator, C@decorator]"
Type parameter "P@X" is invariant, but "P@X" is not the same as "P@decorator"
Type parameter "C@X" is covariant, but "Awaitable[C@decorator]" is not a subtype of "C@decorator"
Type "Awaitable[C@decorator]" cannot be assigned to type "C@decorator" (reportGeneralTypeIssues)
3 errors, 0 warnings, 0 informations
Я уже затронул первое предупреждение (как мне здесь ввести self? приведение его к Base_A не работает, ( имеет send_command/

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

get_response
, но мой декоратор вызывает их с помощью A._marker_property). Более того, поскольку в настоящее время я использую функции, а не декораторы классов, у меня нет возможности добраться до класса A внутри декоратора.
Я мог бы попытаться разделить декоратор в декоратор функции, который отмечает мои функции, и декоратор класса (который будет иметь доступ к базовому классу), но тогда я снова буду жаловаться на присвоение свойств функции.
Мой больший проблема связана с двумя последними ошибками:

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

    "Wrapper" is incompatible with protocol "X[P@decorator, C@decorator]"
Type parameter "P@X" is invariant, but "P@X" is not the same as "P@decorator"
Type parameter "C@X" is covariant, but "Awaitable[C@decorator]" is not a subtype of "C@decorator"
Type "Awaitable[C@decorator]" cannot be assigned to type "C@decorator"
Почему P@X не совпадает с P@decorator (Набор параметров должен быть таким же? И у меня не может быть ковариантного набора параметров...)
И я думал, что набрал правильно, так что Awaitable[C@decorator] ожидается в нужных местах, однако программа проверки типов явно думает иначе.

(Я не контролирую протокол и не могу изменить его дизайн)
РЕДАКТИРОВАТЬ: я был так сосредоточен на завершении/ вывод работать (т.е. для примера редактор знает, что функции возвращают int/

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

Awaitable[int]
), что я на самом деле не проверял эту функциональность. Доступ к self прерывается, и методы родительского объекта не могут быть вызваны:/
Изображение


Подробнее здесь: https://stackoverflow.com/questions/772 ... t-property

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