我知道函数可以有属性。所以我可以做到以下几点:
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
只存在一次。通过x
或y
进行修改会更改相同的值。我希望他们每个人都拥有自己的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
实际上有属性。)
我需要这个的原因是因为我有一个库需要一个具有特定签名的函数。可以将这些函数放入各种管道中,以便按顺序调用它们。我想传递它的相同功能的多个版本,但是根据属性的值改变它们的行为。所以我希望能够将x
和y
添加到管道中,而不是必须实现test1
函数和test2
函数完全相同的事情(属性的值除外)。
答案 0 :(得分:7)
您可以使用__call__
方法创建一个可以实现类似功能的类。
为了清晰起见而编辑而不是使myfunc
成为一个函数,请将其设为可调用类。它像一个函数一样行走,它像一个函数一样嘎嘎叫,但它可以像一个类一样有成员。
答案 1 :(得分: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
的副本与函数一起传递。
答案 2 :(得分: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
答案 3 :(得分: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()
答案 4 :(得分: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
你不能重新使用生成器并操纵数据。