我有一个装饰器,它检查实例属性self.enabled
并在未启用的情况下返回0。否则,它返回方法的返回值(即int),即传入列表中唯一字符串的索引。
def check_if_enabled(func: Callable[..., int]) -> Callable[..., int]:
@wraps(func)
def wrapper(cls, list_of_strings):
if not cls.enabled:
return 0
return func(cls, list_of_strings)
return wrapper
我想使类型注释更具体,但是我不确定如何做。
Callable[..., int]
显然是我要更改的,我想这样做,所以Callable
接受两个参数,一个类的实例和一个字符串列表。这可能吗?
答案 0 :(得分:0)
首先,请记住尽可能提供完整的工作示例。用更多的代码和更少的文字记录您的问题,可以更轻松地理解您要实现的目标,并且对我们造成的误解也较小。
我假设您想装饰一种类似于以下内容的方法:
class Example(object):
@check_if_enabled
def func(self, # implicit Example
list_of_strings: List[str]
) -> int:
pass
首先要做的是确定Callable
的外观。您将函数参数列表作为第一个参数传递,并将返回值作为第二个参数传递。注意,第一个参数是self
,即类实例。因此,可能是:
Callable[[Example, List[str]], int]
或者如果您不想将其限制为一个特定的类:
Callable[[object, List[str]], int]
请注意,您可能需要在声明Example
之前使用此原型。为了允许这样做,您需要传递"Example"
,即类名作为字符串。这被视为该类的前向声明。
因此注释的代码为:
def check_if_enabled(func: Callable[["Example", List[str]], int]
) -> Callable[["Example", List[str]], int]:
@wraps(func)
def wrapper(cls: "Example",
list_of_strings: List[str]
) -> int:
if not cls.enabled:
return 0
return func(cls, list_of_strings)
return wrapper
或作为一个完整的工作示例:
from functools import wraps
from typing import Callable, List
def check_if_enabled(func: Callable[["Example", List[str]], int]
) -> Callable[["Example", List[str]], int]:
@wraps(func)
def wrapper(cls: "Example",
list_of_strings: List[str]
) -> int:
if not cls.enabled:
return 0
return func(cls, list_of_strings)
return wrapper
class Example(object):
def __init__(self, enabled: bool) -> None:
self.enabled = enabled
@check_if_enabled
def func(self, # implicit Example
list_of_strings: List[str]
) -> int:
print('yes, it is')
return 10
ex = Example(True)
print(ex.func(['1', '2', '3']))
ex = Example(False)
print(ex.func(['1', '2', '3']))
产生:
yes, it is
10
0
作为一般说明,您可能希望装饰器是通用的,而不是仅适合一种特定的方法。例如,可以将上述装饰器扩展为适合使用int
和轻松键入的返回*args, **kwargs
的任何方法:
def check_if_enabled(func: Callable[..., int]
) -> Callable[..., int]:
@wraps(func)
def wrapper(cls: "Example",
*args: Any,
**kwargs: Any
) -> int:
if not cls.enabled:
return 0
return func(cls, *args, **kwargs)
return wrapper
更进一步,您可以允许通用返回值,并将其作为参数传递给装饰器:
def check_if_enabled(return_if_disabled: Any
) -> Callable[[Callable[..., int]],
Callable[..., int]]:
def decorator(func: Callable[..., int]
) -> Callable[..., int]:
@wraps(func)
def wrapper(cls: "Example",
*args: Any,
**kwargs: Any
) -> Any:
if not cls.enabled:
return return_if_disabled
return func(cls, *args, **kwargs)
return wrapper
return decorator
class Example(object):
def __init__(self, enabled: bool) -> None:
self.enabled = enabled
@check_if_enabled(return_if_disabled=0)
def func(self, # implicit Example
list_of_strings: List[str]
) -> int:
print('yes, it is')
return -1
当然,这会完全杀死静态类型。
如有疑问,建议您使用mypy。如果输入错误,它可以建议正确的类型。
最后,我不认为@wraps
在这里没有做任何事情。我保留了它,因为它存在于粘贴的代码中。
希望这会有所帮助。