在Python中,如何使用具有与包含功能相同的签名的方法进行装饰班?
这是我要做的事情的示例:
from typing import Callable, Generic, ParamSpec, TypeVar
t_Params = ParamSpec("t_Params")
t_Ret = TypeVar("t_Ret")
class Wraps(Generic[t_Params, t_Ret]):
_func: Callable[t_Params, t_Ret]
def __call__(self, func: Callable[t_Params, t_Ret]):
self._func = func
return self
def call(self, *args: t_Params.args, **kwargs: t_Params.kwargs) -> t_Ret:
return self._func(*args, **kwargs)
@Wraps()
def rep(a: str, b: int, **kwargs):
return a * b
我不想使用__ INIT __
设置self._func
,因为我将无法将其他参数传递到__ INIT __
。
我希望__调用__
方法可以推断t_params
和t_ret
的类型,但这不是:
# mousing over `rep` and `rep.func` shows:
rep # (function) rep: Wraps[(*args: Unknown, **kwargs: Unknown), Unknown]
rep.func # (method) call: (...) -> Unknown
我相信这是因为类型是因为类型AREN' t在创建类实例时被推断出来,而是在调用实例时。
我希望wraps.call
方法具有与包装函数相同的签名。有什么办法做到这一点吗?
编辑以进行进度更新:
如果我远离__调用__
是定义类实例的通用类型的内容,我将制作一个替代构造函数,将其所有参数供应到__ INT __ INT __ INT __ INT __
func
参数之后。但是,我无法给出替代构造函数(.new
)正确的类型提示。
from typing import Callable, Generic, TypeVar
t_WrapsCallable = TypeVar("t_WrapsCallable", contravariant=True, bound=Callable)
t_Callable = TypeVar("t_Callable", bound=Callable)
class Wraps(Generic[t_WrapsCallable]):
func: t_WrapsCallable
def __init__(self, func: t_WrapsCallable):
self.func = func
return self
@classmethod
def new(cls, *args, **kwargs) -> Callable[[t_Callable], "Wraps[t_Callable]"]:
def _new(func: t_Callable) -> Wraps[t_Callable]:
return cls(func, *args, **kwargs)
return _new
@Wraps.new()
def rep(a: str, b: int):
return a * b
rep # (function) rep: Wraps[(a: str, b: int) -> str]
rep.func # (variable) func: (a: str, b: int) -> str
class WrapsWithName(Wraps[t_WrapsCallable]):
def __init__(self, func: t_WrapsCallable, name: str):
super().__init__(func)
self.name = name
@classmethod
def new(cls, name: str) -> Callable[[t_Callable], "WrapsWithName[t_Callable]"]:
# The following line has a type issue:
# Function return type "Wraps[t_Callable@new]" is incompatible with type "WrapsWithName[t_Callable@new]"
# "Wraps[t_Callable@new]" is incompatible with "WrapsWithName[t_Callable@new]"
return super().new(name)
@WrapsWithName.new("repeat")
def rep2(a: str, b: int):
return a * b
rep2 # (function) rep2: WrapsWithName[(a: str, b: int) -> str]
rep2.func # (variable) func: (a: str, b: int) -> str
rep2.name # (variable) name: str
我不能嵌套generic
s,或.new
函数将返回callable [[t_callable],self [t_callable]]
自我是一种与自我阶级结合的typevar。
这使我提出了一个替代问题:python缺乏对高态度类型的支持有什么办法吗?
Here's an example of what I'm trying to do:
from typing import Callable, Generic, ParamSpec, TypeVar
t_Params = ParamSpec("t_Params")
t_Ret = TypeVar("t_Ret")
class Wraps(Generic[t_Params, t_Ret]):
_func: Callable[t_Params, t_Ret]
def __call__(self, func: Callable[t_Params, t_Ret]):
self._func = func
return self
def call(self, *args: t_Params.args, **kwargs: t_Params.kwargs) -> t_Ret:
return self._func(*args, **kwargs)
@Wraps()
def rep(a: str, b: int, **kwargs):
return a * b
I don't want to use __init__
to set self._func
because I would not be able to pass other arguments into __init__
.
I would expect the __call__
method to infer the type of t_Params
and t_Ret
, but it does not:
# mousing over `rep` and `rep.func` shows:
rep # (function) rep: Wraps[(*args: Unknown, **kwargs: Unknown), Unknown]
rep.func # (method) call: (...) -> Unknown
I believe this is because the types aren't being inferred when the class instance is created, but rather when the instance is called.
I want the Wraps.call
method to have the same signature as the wrapped function. Is there any way to do this?
Editing to update with progress:
If I move away from __call__
being what defines the generic types for the class instance, I make an alternate constructor that feeds all of its arguments to __init__
after the func
argument. However, I can't give the alternate constructor (.new
) the correct type hint.
from typing import Callable, Generic, TypeVar
t_WrapsCallable = TypeVar("t_WrapsCallable", contravariant=True, bound=Callable)
t_Callable = TypeVar("t_Callable", bound=Callable)
class Wraps(Generic[t_WrapsCallable]):
func: t_WrapsCallable
def __init__(self, func: t_WrapsCallable):
self.func = func
return self
@classmethod
def new(cls, *args, **kwargs) -> Callable[[t_Callable], "Wraps[t_Callable]"]:
def _new(func: t_Callable) -> Wraps[t_Callable]:
return cls(func, *args, **kwargs)
return _new
@Wraps.new()
def rep(a: str, b: int):
return a * b
rep # (function) rep: Wraps[(a: str, b: int) -> str]
rep.func # (variable) func: (a: str, b: int) -> str
class WrapsWithName(Wraps[t_WrapsCallable]):
def __init__(self, func: t_WrapsCallable, name: str):
super().__init__(func)
self.name = name
@classmethod
def new(cls, name: str) -> Callable[[t_Callable], "WrapsWithName[t_Callable]"]:
# The following line has a type issue:
# Function return type "Wraps[t_Callable@new]" is incompatible with type "WrapsWithName[t_Callable@new]"
# "Wraps[t_Callable@new]" is incompatible with "WrapsWithName[t_Callable@new]"
return super().new(name)
@WrapsWithName.new("repeat")
def rep2(a: str, b: int):
return a * b
rep2 # (function) rep2: WrapsWithName[(a: str, b: int) -> str]
rep2.func # (variable) func: (a: str, b: int) -> str
rep2.name # (variable) name: str
I can't nest Generic
s, or the .new
function would return something like Callable[[t_Callable], Self[t_Callable]]
where Self is a TypeVar that binds to the self's class.
This brings me to an alternate question: Is there a way around Python's lack of support for higher-kinded-types?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论