我想创建装饰器,这将改变返回值的类型:
class TypeDecorators:
def to_int(self, f):
def inner(*args):
try:
return int(f(*args))
except:
return None
return inner
def to_str(self, f):
...
def to_bool(self, f):
...
def to_float(self, f):
...
@TypeDecorators.to_str
def do_nothing(self, string: str):
return string
@TypeDecorators.to_int
def do_something(self, string: str):
return string
print(do_nothing('25'))
print(do_something('25'))
但是它不起作用,有人知道吗?出现此错误:
TypeError: to_str() missing 1 required positional argument: 'f'
答案 0 :(得分:4)
您不需要一堆几乎相同的装饰器。只需定义一个参数化装饰器,以所需的返回类型作为其参数即可。
def change_to(t: type):
def decorator(f):
def wrapper(x):
# Do this first, so you don't catch any exception *it* might raise
rv = f(x)
try:
return t(rv)
except ValueError:
return None
return wrapper
return decorator
@change_to(str):
def do_nothing(x: str):
return x
@change_to_(int):
def do_something(x: str):
return x
答案 1 :(得分:0)
有点晚了,所以我添加了额外的信息,为什么上面显示的带参数的装饰器需要嵌套包装器。
这是基本的装饰器
def deco(func):
print(f"wrapping {func} at IMPORT TIME!")
return func
@deco
def some_function():
pass
即使不调用some_function
脚本也会打印出以下行:
wrapping <function some_function at 0x000001667FB0BCA0> at IMPORT TIME!
由此我们了解到@deco
实际上只是some_function = deco(some_function)
的语法糖。
因此装饰器仅获得一个参数,即目标函数。
但是,对于自变量装饰器,您调用装饰器函数,与普通装饰器不同:
def deco():
print(f"inside deco!") # called on import-time
def inner_deco(func):
print(f"inside inner_deco!") # also called on import-time
def wrapper(*args):
print(f"inside wrapper!") # will be called in run-time
func(*args)
return wrapper
return inner_deco
@deco()
def some_function():
pass
从本质上讲只是一种很酷的方法:
inner_deco = deco()
def b():
pass
b = inner_deco(b)
内置简单装饰器的一个很好的例子是@functools.singledispatch
,另一个是@functools.wraps(original_func)
。
我正在编写相同的解决方案:
from functools import wraps
def typed_decorator(target_type):
def decorator_inner(func):
@wraps(func) # this copy signature of given function to wrapper for easier debugging.
def wrapper(*args):
return target_type(func(*args))
return wrapper
return decorator_inner
@typed_decorator(int)
def do_something(val):
return val
@typed_decorator(bool)
def do_other(val):
return val
print(type(do_something("20")))
print(type(do_other("30")))
<class 'int'>
<class 'bool'>