Python имеет много магии внутри. Одна из этих магий имеет какое-то отношение к преобразованию функций в объекты UnboundMethod (при присвоении классу, а не экземпляру класса).
Когда вы назначаете функцию (И я не уверен, относится ли она к любым вызываемым или справедливым функциям), Python преобразует ее в объект UnboundMethod (т. Е. Объект, который можно вызвать с помощью экземпляра или нет).
В нормальных условиях, вы можете позвонить UnboundMethod как обычно:
def myfunction(a, b):
return a + b
class A(object):
a = myfunction
A.a(1, 2)
#prints 3
Это не подведет. Тем не менее, есть отличный случай, когда вы пытаетесь вызвать его из экземпляра:
A().a(1, 2)
Это потерпит неудачу, поскольку, когда экземпляр получает (скажем, внутренний getattr
) атрибут, который является UnboundMethod, он возвращает копию таких метод с im_self
членом, населенным (im_self
и im_func
являются членами UnboundMethod). Функция, которую вы намеревались вызвать, находится в элементе im_func
. Когда вы вызываете этот метод, вы на самом деле вызываете im_func
с, дополнительно, значением в im_self
. Таким образом, функции требуется дополнительный параметр (первый, который будет стоять за себя).
Чтобы избежать этой магии, Python имеет два возможных декоратор:
- Если вы хотите передать функцию как есть, вы должны использовать
@staticmethod
. В этом случае у вас будет функция, не преобразованная в UnboundMethod. Однако вы не сможете получить доступ к вызывающему классу, за исключением глобальной ссылки.
- Если вы хотите иметь то же самое, но иметь доступ к текущему классу (независимо от того, вызвана ли функция из экземпляра или из класса), ваша функция должна иметь другой первый аргумент (INSTEAD of self: cls), который является ссылкой на класс, а декоратор для использования -
@classmethod
.
Примеры:
class A(object):
a = staticmethod(lambda a, b: a + b)
A.a(1, 2)
A().a(1, 2)
Оба будут работать.
Другой пример:
def add_print(cls, a, b):
print cls.__name__
return a + b
class A(object):
ap = classmethod(add_print)
class B(A):
pass
A.ap(1, 2)
B.ap(1, 2)
A().ap(1, 2)
B().ap(1, 2)
Проверить это, yourseld и пользоваться магией.
Если ему не нужны атрибуты экземпляра/класса, вы можете сделать его '@ staticmethod'. – jonrsharpe
перефразируйте свой вопрос, как перезаписать функции класса в классах потомков? Проверьте эту статью http://lgiordani.com/blog/2014/05/19/method-overriding-in-python/ – AzaFromKaza