请看一个简单的例子:
class A:
def __init__(self, flag):
self.flag = flag
def func(self):
print self.flag
a = A(1)
b = A(2)
callback_a = a.func
callback_b = b.func
callback_a()
callback_b()
结果是:
1
2
按预期运行。但我有一个问题。在C中,回调函数作为指针传递。在Python中,它应该有类似的方法来执行此操作,因此调用者知道函数的地址。但在我的例子中,不仅传递了函数指针,而且传递了参数(self),因为同一类的相同方法打印出不同的结果。所以我的问题是:
Python中的这种方法在内存中只有一个副本吗?我的意思是任何方法的代码只有一个副本,在我的例子中,该方法不会被克隆。我认为它应该只有一个副本,但在这里我仍然提出这个问题以获得更多的输入。
我记得Python中的所有内容都是一个对象。所以在我的例子中,是否有两个具有不同参数但只有一个代码副本的函数实例?
答案 0 :(得分:19)
在Python中,回调不仅仅是对成员函数的引用。相反,它被“绑定”到它创建时引用的对象。因此a.func
创建一个绑定到a
的可调用对象,b.func
创建一个绑定到b
的可调用对象。
Python在内存中只需要func()
的一个实现,但是它可能会在运行时创建一个或多个“trampoline”函数来完成绑定(我不确定这个内部细节,并且它不管怎么说,Python实现之间会有所不同。)
如果您打印id(callback_a)
和id(callback_b)
,您将获得不同的结果,表明它们确实是不同的可调用对象。
答案 1 :(得分:16)
特定于CPython,只有一个函数对象的副本。在实例创建期间,类将未绑定的函数作为绑定方法包装在其名称空间中。但它们都包含相同的功能。
以下是您的示例,以展示正在发生的事情。
class A(object):
def __init__(self, flag):
self.flag = flag
def func(self):
print self.flag
a = A(1)
b = A(2)
callback_a = a.func
callback_b = b.func
print "typeof(callback_a) = {0}".format(type(callback_a))
print "typeof(callback_b) = {0}".format(type(callback_b))
print "typeof(callback_a.__func__) = {0}".format(type(callback_a.__func__))
print "typeof(callback_b.__func__) = {0}".format(type(callback_b.__func__))
print "'callback_a.__func__ is callback_b.__func__' is {0}".format(callback_a.__func__ is callback_b.__func__)
callback_a()
callback_b()
此代码输出
typeof(callback_a) = <type 'instancemethod'>
typeof(callback_b) = <type 'instancemethod'>
typeof(callback_a.__func__) = <type 'function'>
typeof(callback_b.__func__) = <type 'function'>
'callback_a.__func__ is callback_b.__func__' is True
您可以使用is
运算符清楚地看到两个instancemethod
类共享相同的函数对象。