3

合同:函数将函数作为参数并返回函数[即已修改(或相同)版本的函数]。例如,通过函数,这里是square装修工合同

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

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

+2

最常见的情况是返回一个新的函数(一个包装器),它使用传递函数,它不是传递函数的修改版本。 –

+0

@AlexHall修改过的函数我的意思是,无论如何,这个函数使用传递的函数。 – overexchange

+1

好的,我只是想澄清一下,因为有时装饰器可能会简单地设置传入函数的属性,然后将其返回,这是我认为您的修改版本的含义。 –

回答

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 
>>> 
+0

我不明白,但我喜欢。我需要阅读装饰器... – ratskin

+6

@ratskin包括上面的装饰器的功能是一样的后面添加'function = decorator(function)'。 –

+0

没有任何东西阻止我返回任何东西,这是一种错误运用装饰者思想的简单方法。可能你应该删除那个短语,在你的答案 – overexchange

5

装饰函数应该返回一个函数,因为它返回的任何东西都会被绑定到原始函数的名字上。所以如果返回的对象不是一个函数(或者其他一些可调用的,比如一个类的构造函数或者可调用的类实例),那就相当混乱。

通常返回的函数应该有一个与原始函数兼容的函数签名,但我想如果返回的函数也需要额外的参数,那也没关系。另外,返回函数的返回类型应该与原始函数的返回类型兼容。

装饰函数有点像原始函数的子类,所以遵循Liskov substitution principle是有意义的。

装饰功能可能有副作用:例如,它可以修改一些全局。这可能是有用的,例如用于记录目的; OTOH,功能通常应避免有副作用。

FWIW,一些标准函数装饰器返回非函数可调参数,最常见的可能是@classmethod


装饰者没有什么特别的神奇。由于贾里德Goguen在评论中提到,

@decorator 
def some_function(args): 
    #etc 

是相同的

def some_function(args): 
    #etc 

some_function = decorator(some_function) 

第二种形式是长一点,但功能更强大,因为你可以选择返回的功能结合到一个不同的名称, 如果你想。如果不是完全不可能使用@语法,那么使用较长语法可以轻松完成的一些事情可能很困难。

+0

[这里](https://stackoverflow.com/a/34558606/2482744)是一个装饰器的例子,它以非常有用的方式返回非函数。 –

+2

@Alex ???那些是功能......我错过了什么? –

+2

@JaredGoguen lambdas是实际的装饰器,而'skip [除了]'是产生装饰器的函数。所以装饰的功能可以替换为None。 –

-2

装饰可以作为

  • 登记装饰
  • 功能性装饰
  • 参数装饰
  • 基于类的装饰

代码在您的查询是功能装饰,即取代装饰福square)与wrapperwrapper执行以下操作:

  • 电话f(n)
  • 适用floatresult并返回。
def floatify(f): 
    def wrapper(n): 
     result = f(n) 
     return float(result) 
    return wrapper 

功能装饰的合同:

替换功能通常荣誉的装饰功能的合同:

  • 接受小号兼容类型的AME数/种参数的个数
  • 返回结果

替换功能应该从装饰功能

  • 重要的调试和其他的元编程目的保存元数据,使用@functools.wraps(f)