是否可以让Python函数像实例一样工作?

2 投票
5 回答
552 浏览
提问于 2025-04-16 02:38

我知道函数可以有属性。所以我可以这样做:

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函数,它们几乎做的事情完全一样(除了attribute的值)。

5 个回答

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的副本。

7

你可以创建一个包含 __call__ 方法的类,这样就能实现类似的功能。

补充说明:与其把 myfunc 定义成一个函数,不如把它做成一个可以调用的类。它的表现就像一个函数,听起来也像一个函数,但它还可以像类一样拥有成员。

撰写回答