2016-07-07 42 views
-2

RANT - 爲什麼人們說「裝飾器是返回另一個函數的函數」?這個定義沒有意義,因爲如果這是一個裝飾器,那麼爲什麼不使用第二個函數,而不是第一個傻瓜? - 完RANT在Python中對裝飾器進行格式化

幸運的是,我發現這裏一個更合理的定義: http://thecodeship.com/patterns/guide-to-python-function-decorators/

不幸的是,我仍然不明白的例子,像這樣的:

def get_text(name): 
    return "lorem ipsum, {0} dolor sit amet".format(name) 

def p_decorate(func): 
    def func_wrapper(name): 
     return "<p>{0}</p>".format(func(name)) 
    return func_wrapper 

my_get_text = p_decorate(get_text) 

print my_get_text("John") 

#Outputs "<p>lorem ipsum, John dolor sit amet</p>" 

注意,後已有兩年多的時間,作者也沒有迴應任何評論。

我的問題是:爲什麼它不輸出

"<p>John</p>" 

或錯誤?整個字符串如何進入p標籤而不是名稱?

+1

你在混淆函數和函數返回。裝飾器可以根據給定的參數(另一個函數)返回不同的函數。它不會調用它返回的函數,但通常是它返回的函數,*在調用*時調用最初提供給裝飾器的函數。 – zondo

+1

顯然你沒有閱讀那篇文章的其餘部分......它在艱苦的細節中解釋了究竟發生了什麼,目標是什麼,以及如何使用python提供的工具來實現該目標...... –

+0

@JeffMercado:也許這就是爲什麼他提到這篇文章有一個「更明智的定義」......他沒有告訴我們哪篇文章對他沒有意義。 – zondo

回答

3

編輯:我只是意識到你有一個文章鏈接,從字面上解釋了什麼是裝飾器是一步一步......但這已經是打完了所以......

有一個叫Python中關閉/函數閉包功能。

這是一段時間,因爲我試圖解釋/理解在關閉/裝飾器下發生的情況,所以這可能實際上是錯誤的。

功能func_wrapper正在每次p_decorate被稱爲重新定義,並func_wrapper會記住封閉命名空間看起來像在定義什麼時間。

這是什麼意思:

舉個例子,假設你有一些外部變量嵌套在p_decorate中你希望它拋出一個錯誤,因爲它不再存在(它的非本地func_wrapper)時func_wrapper被調用並嘗試使用這個變量,但它不會因爲封閉的命名空間「記住」

在Python 3是__closure__和蟒蛇2這是func_closure下面。

def get_text(name): 
    return "lorem ipsum, {0} dolor sit amet".format(name) 

def p_decorate(func): 
    def func_wrapper(name): 
     return "<p>{0}</p>".format(func(name)) #Cached result 
    print(func_wrapper.func_closure) 
    return func_wrapper 

my_get_text1 = p_decorate(get_text) 
my_get_text2 = p_decorate(get_text2) 

func_closure東西:

my_get_text1 >>> (<cell at 0x*: function object at 0x*>,) 
my_get_text2 >>> (<cell at 0x(different address): function object at (diff address)>,) 

我們不是通過不同功能的func_wrapper功能,但正在建設的func_wrapper功能「記住」什麼功能,應該通過func調用的自定義版本。

如果你在同一個函數傳遞兩次my_get_text1my_get_text2你必須爲func_wrapper.func_closure位,內存地址,一切都完全一樣的事情function object at *,因爲它是相同的功能。 (當你用一個潛在的不同的參數實際調用它時減去。)

裝飾

裝飾器是正如你指出一個簡單的調用,需要一個函數作爲參數,並返回一個替換功能。在你的代碼中,這將分別是p_decoratorfunc_wrapper

如果你想在面向對象的方式思考這個......你能想到的p_decorate作爲功能func_wrapper構造與FUNC像個私有成員變量/屬性,因爲你已經或多或少基本建成與功能一個硬編碼的參數func

爲什麼它返回它做什麼:

希望上面是正確的+有道理......然後,返回你看,因爲你已經通過了get_text功能被「記住」的價值,因爲func_wrapper返回...你用的John參數調用func_wrapper(arg)現在這裏面... func_wrapper返回如下:

"<p>{0}</p>".format(func(name))" 

隨着funcget_text。所以,get_text被稱爲返回...

"lorem ipsum, {0} dolor sit amet".format(name) 

然後這是開口之間格式化和關閉p標記,然後返回。

你可以有多層嵌套的函數,就像python中的任何東西一樣,它都是烏龜。

爲什麼即使打擾使用裝飾?

在這個例子中,我認爲你是對的,我只是使用第二個函數,因爲這是一個非常沒用的例子。

但是,考慮更具體的東西。我會用一個普通的django裝飾器作爲我的頭頂的例子。即使你不熟悉Django,這應該仍然有意義。

在django中,您有可以呈現網頁的函數/視圖,有時您可能想要用戶登錄才能查看頁面。現在

,你要想這對,如果你有寫自定義邏輯每一個功能什麼。

這將是可怕的。相反,有一個名爲@login_required的漂亮的裝飾器,您只需將它放在您希望使用此功能的函數的頂部,並且您只需保存大量時間/重複的代碼即可,因爲此裝飾器將此自定義邏輯封裝在您已應用它的函數。

裝飾器主要用於想要擴展/自定義功能而無需重新編碼所有內容。

甚至比功能更進一步...如果您想將此應用於class的方法,該怎麼辦?也許他們都滿足某些標準?它會變得乏味,並且可能讓人煩惱,因爲每一種方法都必須這樣做。您可以編寫一個裝飾器來包裝類,並將其應用於每個函數,並自動爲您自動創建一個函數,而不是使用@decorator_name包裝每一種方法。

+0

我需要看看我是否可以把它放在我自己的英文中,看看我是否理解你: 返回包裝在p標籤中的參數(名稱),但是以原始函數get_text的格式返回,所以結果全部變成「lorem ipsum,John dolor sit amet」 因此變量{0}既不被替換也不被覆蓋,而是'格式化'以符合原始函數。那有意義嗎?這是一個正確的簡單英語解釋嗎? –

+1

我想我遵循你所說的話,如果是,那麼是的。 get_text中的{0}不受'func_wrapper'中的{0}影響。當'func_wrapper'調用'func(name)'時,它返回字符串''lorem ipsum,John dolor sit amet'',它是通過將'name'格式化到'get_text'的'{0}'中創建的,然後這個字符串是格式化爲'func_wrapper'中的'{0}'。所以,你有'

(由get_text返回的字符串)

'func_wrapper' – Pythonista