2010-08-11 75 views
2

我知道函數可以有屬性。所以我可以做到以下幾點:是否有可能使Python函數的行爲像實例一樣?

def myfunc(): 
    myfunc.attribute += 1 
    print(myfunc.attribute) 

myfunc.attribute = 1 

是否有可能通過任何方式使這樣一個函數的行爲,如果它是一個實例?例如,我希望能夠做這樣的事情:

x = clever_wrapper(myfunc) 
y = clever_wrapper(myfunc) 
x.attribute = 5 
y.attribute = 9 
x() # I want this to print 6 (from the 5 plus increment) 
y() # I want this to print 10 (from the 9 plus increment) 

既然這樣,有功能的只有一個「實例」,所以attribute只存在一次。通過xy修改它會更改相同的值。我希望他們每個人都有自己的attribute。這有可能做到嗎?如果是這樣,你能提供一個簡單的功能性例子嗎?

重要的是,我可以從函數內部訪問attribute,但取值爲attribute的值根據函數的哪個「實例」被調用而不同。本質上,我想使用attribute就好像它是函數的另一個參數(以便它可以改變函數的行爲),但不會將其傳入。(假設函數的簽名是固定的,所以我不能更改參數列表。)但我需要能夠設置attribute的不同值,然後按順序調用函數。我希望這是有道理的。

主要答案似乎在說做這樣的事情:

class wrapper(object): 
    def __init__(self, target): 
     self.target = target 
    def __call__(self, *args, **kwargs): 
     return self.target(*args, **kwargs) 

def test(a): 
    return a + test.attribute 

x = wrapper(test) 
y = wrapper(test) 
x.attribute = 2 
y.attribute = 3 
print(x.attribute) 
print(y.attribute) 
print(x(3)) 
print(y(7)) 

但是,這並不工作。也許我做錯了,但它說test沒有attribute。 (我假設這是因爲wrapper實際上具有該屬性。)

我需要這個的原因是因爲我有一個庫,期望具有特定簽名的函數。可以將這些函數放入各種管道中,以便它們按順序調用。我想通過它的同一個函數的多個版本,但基於屬性的值來改變它們的行爲。所以我希望能夠將xy添加到流水線中,而不是必須實現test1函數和test2函數,它們的功能幾乎完全相同(除了屬性的值)。

+0

是否有任何特定的原因,你想要一個功能,而不是一個類?這僅僅是爲了教育目的,還是有一個真正的問題,你正試圖解決? – 2010-08-11 15:17:30

+0

類名應該是PascalCase :) – 2010-08-11 15:41:58

+0

試試我的答案。我測試了它,它工作 – 2010-08-11 15:43:14

回答

7

你可以用__call__方法做一個類,它可以實現類似的功能。

編輯清晰度:而不是使myfunc函數,使其成爲一個可調用的類。它像一個函數一樣走路,它像一個函數一樣嘎嘎作響,但它可以讓成員像一個類一樣。

+0

我需要能夠訪問函數內的屬性。這仍然可以使用你的方法嗎? – agarrett 2010-08-11 15:08:05

+1

是的;但他現在正在使用一個類(作爲一個函數),而不是一個簡單的函數。 – 2010-08-11 15:16:26

+5

是的,你可以訪問任何一個班級的成員。我們都在這裏同意大人,我們沒有私人成員;) – 2010-08-11 15:16:38

0
#!/usr/bin/env python 
# encoding: utf-8 

class Callable(object): 
    attribute = 0 

    def __call__(self, *args, **kwargs): 
     return self.attribute 

def main(): 
    c = Callable() 
    c.attribute += 1 
    print c() 


if __name__ == '__main__': 
    main() 
+1

+1例如,-1用於混合類和實例變量= +0 – delnan 2010-08-11 15:19:16

+0

我的印象是創建一個類的新實例作爲類的字典副本。否則,它將如何通過自我獲得?我只是用它作爲初始化器。看到一個例子:http://gist.github.com/519150 – 2010-08-11 15:23:36

+0

你錯過了屬性+ = 1 – 2010-08-11 15:28:51

0

發電機可能是這裏的另一種解決方案:

def incgen(init): 
    while True: 
     init += 1 
     print init 
     yield 

x = incgen(5) 
y = incgen(9) 

x.next() # prints 6 
y.next() # prints 10 
y.next() # prints 11 
x.next() # prints 7 

不能挖回來的發電機,雖然操縱數據。

1
class Callable(object): 
    def __init__(self, x): 
     self.x = x 

    def __call__(self): 
     self.x += 1 
     print self.x 

>> c1 = Callable(5) 
>> c2 = Callable(20) 
>> c1() 
6 
>> c1() 
7 
>> c2() 
21 
>> c2() 
22 
2

一個更好的辦法:

def funfactory(attribute): 
    def func(*args, **kwargs): 
     # stuff 
     print(attribute) 
     # more stuff 

    return func 

x = funfactory(1) 
y = funfactory(2) 

x() # 1 
y() # 2 

這工作,因爲該功能是關閉,所以他們會搶他們的範圍內的所有局部變量;這導致attribute的副本被傳遞給函數。

+0

嗚!功能:) – Skilldrick 2010-08-11 17:02:16

相關問題