2017-01-30 101 views
1

在JavaScript我可能會寫這樣的功能:是否有更多'pythonic'的方式來編寫這個閉包?

function counter() { 
    foo = 0; 
    function increment() { 
    foo += 1 
    console.log(foo); 
    } 
    function printVal() { 
    console.log(foo); 
    } 

    return { 
       increment: increment, 
      printVal: printVal, 
        }  
} 

func = counter(); 

func.increment() 
func.increment() 
func.printVal() 

我想嘗試使用Python來實現類似的功能。特別是我如何通過外部函數的返回來訪問兩個內部函數。

這裏是一個工作,但好笑的看着,版本蟒蛇:

def counter(): 
    foo = {'bar': 0} 
    def increment(): 
     foo['bar'] += 1 
     return foo['bar'] 
    def printVal(): 
     return foo['bar'] 
    return {'increment': increment, 'printVal': printVal} 

func = counter() 
func['increment']() 
func['printVal']() 

是否有某種寫這樣一個封閉的更優雅或「Python化」的方式?

+2

在這種情況下,您可能想要使用'collections.Counter'對象,或者只寫一個類。 – monkut

+1

你應該問自己,爲什麼你首先在JS中使用閉包:閉包常常是_classlike_行爲的替代品。在python的情況下,你可以使用'class'來模擬accoring行爲。你的兩個函數變成_real_方法。 –

回答

1

簡單地實現__getitem__

class Foo: 
    class_attributes = {'a': 3, 
         'b': 5} 

    def __getitem__(self, name): 
     return Foo.class_attributes[name] 


f = Foo() 
print f['a'] 

輸出:

3 
+0

相同的class_attributes是否可用於Foo的所有實例? – fafl

+0

在這個例子中它會。通過實現構造函數可以定義每個實例的class_attributes。 – AndreyF

0

我認爲你想達到什麼是像下面的例子:

def makeInc(x): 
    def inc(y): 
    # x is "attached" in the definition of inc 
    return y + x 

    return inc 

incOne = makeInc(1) 
incFive = makeInc(5) 

incOne (5) # returns 6 
incFive(5) # returns 10 

你想要的Python的方式創建關閉。所以上面的例子演示瞭如何做到這一點。

3

Python不像其他語言那樣強大。首先,它只支持讀取「關閉」變量,其次,return聲明使其更加尷尬。

在另一方面,這是非常簡潔的帶班,因此,如果你想有一個數據成員有兩個功能,我會用一個類來完成它:

class Counter: 
    def __init__(self, c=0): 
     self.count = c 
    def increment(self): 
     self.count += 1 
    def printVal(self): 
     return self.count 


c = Counter() 
c.increment() 
print(c.printVal()) 

我敢說,在這種情況下,這將是pythonic的方式。

編輯

看到有關跟蹤函數調用您的評論後,我想補充這一點。您可以通過封閉令,就像這樣:

# this is the tracked function 
def add2(a, b): 
    return a + b 

# this is the count tracker 
def counterize(func): 
    c = [0] 
    def counter_func(*args, **kw): 
     c[0] += 1 
     counter_func.count = c[0] 
     return func(*args, **kw) 
    return counter_func 


cadd2 = counterize(add2) 

print(cadd2(1, 2)) 
print(cadd2(3, 4)) 
print('Called %s times' % cadd2.count) 

>>> 
3 
7 
Called 2 times 

但是,這不是地道的Python編寫的。在函數對象內部保留count是一個不錯的訣竅,但這就是它的原因。一個惡作劇。另一方面,在LISP或Scala中,封閉會更自然,但是,我認爲將count作爲一個字段是不可能的,但是,將它與結果一起返回。

我要說的是,在這種情況下,再次慣用的Python代碼將通過類,它是更易於理解海事組織和長度相同的代碼:

class Counterize: 
    def __init__(self, func): 
     self.func = func 
     self.count = 0 
    def __call__(self, *args, **kwargs): 
     self.count += 1 
     return self.func(*args, **kwargs) 


cadd2 = Counterize(add2) 
print(cadd2(1, 2)) 
print(cadd2(3, 4)) 
print('Called %s times' % cadd2.count) 

和輸出將是相同。 __call__的目的是允許通過括號調用將對象作爲函數來處理。

+0

謝謝,我希望能夠使用閉包,因爲我正在努力學習更多功能性技巧,但這看起來像迄今爲止的最佳解決方案。我想要做的更大的事情是有一個計數器,我可以使用它來跟蹤函數被調用的次數。 –

相關問題