Правда ли, что "набор методов, тем не менее, фиксируется при первом определении класса"?
С прагматики языка программирования, Скотт
И Python, и Ruby более гибки, чем PHP или более традиционные object- ориентированные языки в отношении содержимого (членов) класса. Новые поля могут быть добавлены в объект Python, просто присваивая им: my_object.new_field = value. Однако набор методов фиксируется при первом определении класса. В Ruby только методы видны вне класса (методы "put" и "get" должны использоваться для доступа к полям), и все методы должны быть явно объявлены. Однако можно изменить существующее объявление класса, добавив или переопределив методы. Можно даже сделать это на основе объекта object-. В результате два объекта одного и того же класса могут не отображать одинаковое поведение.
Что означает "набор методов, однако, фиксируется при первом определении класса"?
Кажется, я нашел контрпример:
>>> class E:
... pass
...
>>> E.__dict__
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'E' objects>, '__doc__': None, '__weakref__': <attribute '__weakref__' of 'E' objects>})
>>> def myfun():
... pass
...
>>> E.mf=myfun
>>> E.__dict__
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'E' objects>, '__doc__': None, '__weakref__': <attribute '__weakref__' of 'E' objects>, 'mf': <function myfun at 0x7f6561daba60>})
Ответы
Ответ 1
Как показано в вопросе: тривиально добавить функцию к объекту класса, который ведет себя точно так же, как любой метод:
def fake_method(self,idx):
print(self, idx)
class MyClass(object):
pass
MyClass.new_method = fake_method
n = MyClass()
n.new_method(10)
# <__main__.MyClass object at 0x000001BBA6E90860> 10
Вы также можете добавить экземпляр "вызываемых атрибутов" типа "method":
import types
def fake_method(self,idx):
print(self, idx)
class MyClass(object):
pass
n = MyClass()
n.new_method = types.MethodType(fake_method, n)
n.new_method(10)
# <__main__.MyClass object at 0x000001BBA6E9C2E8> 10
Здесь нужен types.MethodType
, потому что в противном случае он будет вести себя как a staticmethod
.
Мое резюме: Либо я пропущу какой-то критический момент цитаты, либо это неправильно.
Ответ 2
На уровне экземпляра можно напрямую изменять поля, как указано.
На уровне класса/модуля существует неофициальная механика под названием monkey patching
. В основном вы получите ссылку (?) На класс/модуль и переопределите функцию.
Однако мне не ясно, могут ли быть отменены статические методы. И модификация действительна только в локальной области, где, как мне кажется, сделаны патчи для обезьян. Поэтому вы не должны ожидать, что другие сценарии импортируют один и тот же класс/модуль для совместного использования патчей обезьян, если они также не будут применять исправления явно. Конечно, вы также можете создать оберточный модуль.
Я не думаю, что сообщество Python сильно защищено. Трудно держать патчи в течение долгого времени.
Дополнительная информация: Что такое патч обезьяны?