是否可以让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
只存在一次。用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
函数,它们几乎做的事情完全一样(除了attribute
的值)。
5 个回答
在编程中,有时候我们会遇到一些问题,比如代码运行不正常或者出现错误。这些问题可能是因为我们没有正确理解某些概念,或者在写代码时犯了一些小错误。
如果你在学习编程,遇到不懂的地方,别担心,这很正常。很多人都是从基础开始学起,慢慢积累经验的。重要的是要保持耐心,多问问题,寻找解决方案。
记住,编程就像学习一门新语言,刚开始可能会觉得困难,但只要坚持练习,你就会越来越熟练。
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
更简单的方法:
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
的副本。
你可以创建一个包含 __call__
方法的类,这样就能实现类似的功能。
补充说明:与其把 myfunc
定义成一个函数,不如把它做成一个可以调用的类。它的表现就像一个函数,听起来也像一个函数,但它还可以像类一样拥有成员。