Как Python отличает функцию обратного вызова, которая является членом класса?
Пожалуйста, посмотрите на простой пример:
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 является объектом. Итак, в моем примере есть два экземпляра функции с разными параметрами, но только одна копия кода?
Ответы
Ответ 1
Конкретно для 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
используют один и тот же функциональный объект.
Ответ 2
В Python обратный вызов - это не просто ссылка на функцию-член. Вместо этого он "привязан" к объекту, к которому он относится, когда он был создан. Поэтому a.func
создает вызываемый, привязанный к a
, а b.func
создает вызываемый, привязанный к b
.
Python требует только одну реализацию func()
в памяти, но она, вероятно, создаст одну или несколько "батутных" функций во время выполнения, чтобы выполнить привязку (я не уверен в внутренних деталях этого, и это будет отличаться между реализацией Python).
Если вы печатаете id(callback_a)
и id(callback_b)
, вы получите разные результаты, показывая, что они действительно разные вызываемые объекты.