__init__
метод вашего класса добавляет связанный метод в качестве атрибута в случаях вашего класса. Это не совсем то же самое, что добавлять атрибут в класс. Обычно методы работают, сохраняя функции в классе как атрибуты, а затем создавая объекты метода , поскольку эти функции извлекаются как атрибуты из класса (создание несвязанных методов, которые знают только класс, к которому они принадлежат) или экземпляр (создание которые знают их экземпляр.)
Как это отличается от того, что вы делаете? Ну, вы назначаете экземпляр атрибут специфический экземпляр, а не класс. Связанный метод становится частью данных этого экземпляра:
>>> s.__dict__
{'GET': <bound method Sub.get of <__main__.Sub object at 0xb70896cc>>}
Обратите внимание, как метод есть под ключ GET
, но не под get
. GET
- атрибут экземпляра, но get
- нет. Это несколько отличается несколькими способами: метод не существует в объекте класса, поэтому вы не можете сделать Sub.GET(instance)
для вызова метода Sub
GET
, хотя вы можете сделать Sub.get(instance)
. Во-вторых, если у вас есть подкласс Sub, который определяет свой собственный метод GET
но не его собственный метод get
атрибут экземпляра будет скрыть метод подкласс GET
с связанного get
методом из BaseClass. В-третьих, он создает круговую ссылку между связанным методом и экземпляром: связанный метод имеет ссылку на экземпляр, и экземпляр теперь сохраняет ссылку на связанный метод. Обычно методы ограничения не сохраняются на экземпляре частично, чтобы избежать этого. Циркулярные ссылки обычно не являются большой проблемой, потому что в настоящее время у нас есть модуль cyclic-gc (gc
), который заботится о них, но он не всегда может очищать эталонные циклы (например, когда ваш класс также имеет метод __del__
.) И, наконец, хранение объектов связанных объектов обычно делает ваши экземпляры неэриализуемыми: большинство сериализаторов (например, pickle
) не могут обрабатывать связанные методы.
Возможно, вам не все в порядке по этим вопросам, но если вы это сделаете, есть лучший подход к тому, что вы пытаетесь сделать: метаклассы. Вместо назначения связанных методов экземпляра атрибутов, как создавать экземпляры, вы можете назначить нормальные функции класса атрибуты, как вы создаете класс:
class MethodAliasingType(type):
def __init__(self, name, bases, attrs):
# attrs is the dict of attributes that was used to create the
# class 'self', modifying it has no effect on the class.
# So use setattr() to set the attribute.
for k, v in attrs.iteritems():
if not hasattr(self, k.upper()):
setattr(self, k.upper(), v)
super(MethodAliasingType, self).__init__(name, bases, attrs)
class Base(object):
__metaclass__ = MethodAliasingType
class Sub(Base):
def get(self):
pass
Теперь Sub.get
и Sub.GET
действительно являются псевдонимами, и перекрывая один и не другие в подклассе работают, как ожидалось.
>>> Sub.get
<unbound method Sub.get>
>>> Sub.GET
<unbound method Sub.get>
>>> Sub().get
<bound method Sub.get of <__main__.Sub object at 0xb708978c>>
>>> Sub().GET
<bound method Sub.get of <__main__.Sub object at 0xb7089a6c>>
>>> Sub().__dict__
{}
(Конечно, если вы не хотите перекрывая один, а не другой работы, вы можете просто сделать это ошибка в вашем метакласса.) Вы можете сделать то же самое, что и метакласса с использованием декораторов классов (в Python 2.6 и более поздних), но это означало бы, что требовать, чтобы декоратор класса на каждом подклассе декораторов базового класса не был унаследован.
Тогда я бы повторил. Но он работает после инстанцирования, как показал «S.Mark». – deamon