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)