2016-01-19 97 views
0

在Python 3,你可以這樣創建類:創建一個仿函數的調用類或嵌套函數

class foo: 
    def __init__(self, x): 
     self.x=x 

    def __call__(self, y): 
     self.x = self.x + 1 
     return (self.x, y) 

然後可以用這樣的狀態把它作爲一個函子:

functor = foo(5) 
x = 44354234 
print('(1.1) ', functor(7)) 
print('(1.2) ', functor(8)) 
print('(1.2) ', functor(9)) 

在實踐中,我創建了一個返回函數的函數。但是,這第一個函數實際上是一個返回可調用對象的構造函數。恕我直言,這可以通過允許開發人員擴展類,添加方法等來打開一堆蠕蟲。此外,__init__中的代碼在某種程度上自然地先於__call__中的代碼,因爲它需要執行,並且在類結構。最後,Python 3'的方式'建議使用函數而不是類。

爲此,我創建的類的一個類似功能的版本,它具有較小的樣板代碼和恕我直言,讀取更自然:

def bar(x): 
    def f(y): 
     nonlocal x 
     x = x + 1 
     return (x,y) 
    return f 

functor2 = bar(5) 
x = 345234234 
print('(2.1) ', functor2(7)) 
print('(2.2) ', functor2(8)) 
print('(2.3) ', functor2(9)) 

但是,它使用nonlocal,可能不直觀的原因,我有沒有想到。第二種方法是不錯的做法,還是存在危險的剔骨? Python 3中應該首選哪個?特別是因爲我幾乎沒有使用nonlocal的經驗。

+1

*「恕我直言,這允許開發者來擴展類打開了一罐蠕蟲」 * - 這是一件壞事,爲什麼?另外,我不確定問題是什麼。哪些會被優先考慮?使用更有意義的東西。 – poke

+2

「此外,__init__中的代碼自然先於__call__中的代碼,因爲它需要執行,而且在類構造中不明確。」 =>它**清楚地表明初始化__將在它甚至可以調用'__call__'之前被執行。 –

+2

「最後,Python 3'的方式'建議使用函數而不是類':章節和詩歌?無論版本FWIW如何,「Python方式」都是使用對當前任務有意義的構造。在這種情況下,兩者都是有意義的,但第一個允許子類化和簡單的檢查。 –

回答

1

在最近幾年的Python開發策略看起來像是「讓我們將Python中的每個功能都納入其他語言」,這導致了以各種方式完成單個任務的能力。

因此,有些事情確實沒有「首選方式」,這完全取決於開發人員想要做什麼。因此在某些情況下可能需要使用Class來創建有狀態函數並允許擴展它。使用閉合與nonlocal是更常見的IMO,並沒有什麼非直觀的。另一個問題是,當將這種方法用於方法裝飾器時,然後使用函數編寫更少的代碼,並且由於類型self,您將不得不添加更多的「魔術」。

P.S.在Python中,函數可以具有屬性,因此對代碼進行編碼的另一種方法是使用x作爲f內部函數的屬性,而不是nonlocal,儘管它與您所描述的方法不太一樣。

def bar(x): 
    def f(y): 
     f.x=f.x+1 
     return (f.x, y) 
    f.x=x 
    return f 

編輯:增加了額外的縮進return語句

+0

儘管您的解決方案等同於全局變量,因爲「x」的值綁定到函數,而不是實際的函數對象。 – poke

+0

確實。改進它,儘管以前的版本仍然有效。 – Nikita