装饰师的合同

时间:2017-08-11 17:24:03

标签: python python-2.7 python-3.x metaprogramming python-decorators

合同:一个函数,它将函数作为参数并返回一个函数[即,传递函数的修改(或相同)版本]。传递函数,例如,square

@floatify
def square(n):
   return n*n

装饰者是否只返回传递函数的装饰版本,但没有别的?

3 个答案:

答案 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)

功能装饰器的合同

替换功能通常会尊重装饰功能的合约:

  • 接受相同数量/种类的args
  • 返回兼容类型的结果

替换功能应保留装饰功能

中的元数据
  • 对于调试和其他元编程目的很重要,请使用{{1}}