合同:一个函数,它将函数作为参数并返回一个函数[即,传递函数的修改(或相同)版本]。传递函数,例如,square
。
@floatify
def square(n):
return n*n
装饰者是否只返回传递函数的装饰版本,但没有别的?
答案 0 :(得分:7)
它应该只返回一个函数,但没有什么能阻止你返回任何你想要的东西。
>>> def d(x):
... return "hello"
...
>>> @d
... def f():
... return "world"
...
>>> f
'hello'
>>> f()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
>>>
答案 1 :(得分:5)
装饰函数应该返回一个函数,因为无论它返回什么都将绑定到原始函数的名称。如果返回的对象不是函数(或其他一些可调用的,如类构造函数或可调用的类实例),那么它会相当混乱。
一般来说,返回的函数应该具有与原始函数兼容的函数签名,但是如果返回的函数也需要额外的args,我想这没关系。此外,返回函数的返回类型应该与原始函数的返回类型兼容。
装饰函数有点像原始函数的子类,因此遵循Liskov substitution principle是有意义的。
装饰功能可能有副作用:例如,它可以修改一些全局。这可能是有用的,例如用于记录目的; OTOH,功能一般应该避免副作用。
FWIW,一些标准函数装饰器返回非函数可调用函数,最常见的可能是@classmethod
。
装饰者没什么特别神奇的。正如Jared Goguen在评论中提到的那样,
@decorator
def some_function(args):
#etc
与
相同def some_function(args):
#etc
some_function = decorator(some_function)
第二种形式有点长,但功能更强大,因为如果需要,您可以选择将返回的函数绑定到其他名称。如果使用@
语法无法做到这一点,那么使用较长语法可以轻松完成的一些事情可能很困难。
答案 2 :(得分:-3)
装饰器可以用作
您的查询中的代码是功能装饰器,用wrapper
替换修饰函数(wrapper
)。 f(n)
执行以下操作:
float
result
应用于def floatify(f):
def wrapper(n):
result = f(n)
return float(result)
return wrapper
并将其返回。@functools.wraps(f)
功能装饰器的合同 :
替换功能通常会尊重装饰功能的合约:
替换功能应保留装饰功能
中的元数据