2016-05-05 37 views
2

我很困惑三者之間。據我所知,閉包是由另一個函數返回的功能,可以訪問本地變量形成一個封閉範圍閉合,部分和裝飾

例如:

def add_nums(one): 
    def adder(two): 
     return one+two 
    return adder 

a_10 = add_nums(10) 
print a_10(5) 
15 

這裏,adder是一個封閉。

但是,這是不是也是一個partial

from functools import partial 
a_10 = partial(add_nums, 10) 
print a_10()(5) 
15 

是什麼兩者之間的區別的例子嗎?

另外,裝飾器用於爲功能添加功能。

def add_nums(one): 
    def adder(two): 
     print "foo, bar" 
     return one+two 
    return adder 

a_10 = add_nums(10) 
print a_10(5) 
foo, bar 
15 

所有三者之間的區別是什麼?

+0

裝飾器只是一個接受函數並返回函數的函數。由於這通常涉及嵌套函數,因此通過閉包訪問參數函數是很常見的,其中內部函數捕獲它的環境,但我想你可以用部分實現它,而不是顯式傳遞值。目前還不清楚你想知道什麼。 – jonrsharpe

回答

-1

你的裝飾的部分版本實際上是:

def add_nums(one): 
    def adder(one, two): 
     return one + two 
    return partial(adder, one) 

注意,嵌套函數現在只使用明確的參數,關閉。你可以實現一個裝飾器,它只是一個函數,它使用一個函數並返回一個(通常是不同的)函數,使用閉包,partial(即implemented using a closure)或兩者的組合。

+0

你把封閉當作一件事情。用你的話說,封閉究竟是什麼? –

+0

閉包是函數調用時可用的環境,其基礎是創建它的位置。請注意,在閉包版本中,內部函數可以隱式地訪問'one',而不是顯式參數或全局變量*,因爲它可以在創建函數的地方使用*。 – jonrsharpe

2

簡答題:關閉是機制,而functools.partial和裝飾器是該機制的典型用途。

閉包和更典型的命名空間的關鍵區別在於,當「控制流」離開頂層函數時,「閉包」命名空間中的名稱和值不會消失。它們被保存在與內部函數的一個實例相關聯的迷你名稱空間中,並且只要該實例存在就會存活。

functools.partial使用該能力來「記憶」一些先前存在的函數的參數。裝飾者通常也使用該能力出於同樣的原因。

請注意,裝飾器比這更靈活。任何需要一個參數並返回一些東西的可調用函數都可以作爲裝飾器。它沒有來使用Python關閉,甚至返回一個函數。許多裝飾器會返回一個可調用的對象。 (順便說一句,閉合和內部功能可使用的命名空間的對象和用於所述內功能的方法模擬。)無論裝飾返回分配給該名稱的裝飾功能將具有

了。 (與後他們括號裝飾,像@decorator('args') ...是稍微複雜一些。)典型的裝飾語法:

@decorator 
def function(): 
    pass 

...只是對「定義,然後裝飾和重新分配」的簡寫:

def function(): 
    pass 
function = decorator(function) 

對於一個極端的(而且大多無用)例如:

def decorator5(__): 
    return 5 

@decorator5 
def square(x): 
    return x * x 

print(square) # Prints 5 --- the function is gone. 
square(10)  # TypeError: 'int' object is not callable 
3

我想你混淆目的實施。創建閉包是一種處理事務的技巧。你可以用閉包做一堆事情。

另一方面,partialdecorator是特定目的。也許他們使用閉包。也許他們沒有。這是一個實現細節,你不需要擔心它。重要的是他們能夠達到你想要的結果。

考慮一個partial。 (忽略** kwargs)來創建它是使用一個封閉的一種方法:

def partial(f, *args): 
    def pf(*rest): 
     return f(*args, *rest) 
    return pf 

但它並不一定是這樣的。例如:

class Partial: 
    def __init__(self, func, args): 
     self.args = args 
     self.func = func 

    def __call__(self, *rest): 
     f = self.func 
     args = self.args 
     return f(*args, *rest) 

def partial(f, *args): 
    return Partial(f, args) 

這裏沒有關閉,只是一個變量,持有對其他變量的引用。但是我得到了部分的行爲,那麼誰在乎呢?

裝飾者也是如此。一個裝飾器可能是一個閉包,或者它可能不是。例如,最近的一個問題涉及在函數的__doc__字符串上運行str.format。這只是接受函數對象,修改__doc__屬性並返回相同對象的一種情況。很明顯,這不涉及任何關閉。