2010-08-11 27 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

相关问题