Python как получить базовый экземпляр экземпляра? - PullRequest
4 голосов
/ 01 декабря 2011

В C # я бы сказал:

myObj.base

У меня есть класс Date, который наследуется от date.datetime. Класс Date переопределяет __gt__() и __lt__(), поэтому при использовании операторов < и > они вызываются. Я не хочу использовать эти переопределения - я хочу использовать методы date.datetime в экземпляре Date.

Ответы [ 2 ]

6 голосов
/ 01 декабря 2011

Используйте super(), чтобы получить объект суперкласса.Введите help(super) в командной строке Python.

Из руководства:

class super(object)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)
 |  Typical use to call a cooperative superclass method:
 |  class C(B):
 |      def meth(self, arg):
 |          super(C, self).meth(arg)
3 голосов
/ 01 декабря 2011

Если я правильно понимаю ваш вопрос, это не имеет смысла в Python.В экземпляре подкласса нет "базового экземпляра".

Экземпляр Python - это всего лишь одно, содержащее коллекцию атрибутов (любой из которых может быть установлен / изменен любым из его базовых классов, илидействительно из кода вне любого из его классов вообще).Действительно, можно изменить класс экземпляра во время выполнения , даже перенеся его в совершенно иную иерархию наследования (это не всегда хорошая идея, но она четко определена).Независимо от того, что экземпляр остается единым унитарным объектом, который знает только, какие атрибуты он имеет, и к какому классу он относится (и фактически это просто атрибут: __class__).

Редактировать: Если вы хотите иметь возможность вызывать переопределенные методы в экземпляре, то вы делаете это с помощью super, как ответил hocl.Однако, как видно из ваших комментариев, вы не полностью понимаете, что делает super (что естественно, поскольку это довольно сложно).

super(Date, myObj) не возвращает «базовый экземпляр datetime.date»потому что такого нет, только объект myObj.Хотя для ваших целей это звучит так, как будто это удовлетворит ваши потребности (и вы, вероятно, можете остановиться на этом предложении).

То, что он делает, возвращает магическую оболочку вокруг myObj, которая ищет методы, начинающиеся сразу "позади""Date;то есть он находит метод, который будет вызван, если Date не переопределит его.Так что в этом случае он найдет все методы из datetime.date, потому что у вас происходит только одно наследование.

Ключевое отличие состоит в том, что это поддерживает множественное наследование.Если кто-то создает другой класс, который наследует от Date, а также наследует от datetime.date по другому пути, то super(Date, instanceOfThatClass) может на самом деле не попадать в методы datetime.date.Это зависит от деталей наследственной наследственности.Это на самом деле ситуация, для которой super был разработан, хотя;это позволило классам в сложных иерархиях множественного наследования совместно вызывать реализации друг друга, гарантируя, что каждый вызывается только один раз, и в разумном порядке (хотя это может быть не тот же порядок для каждого конечного конечного класса, поэтому классы в серединеиерархии на самом деле не знаю, какую реализацию суперкласса они называют ).Насколько я понимаю, эта сложная ситуация не может возникнуть в C #, поэтому она может обеспечить простой синтаксис .base.

Мое понимание также (и это немного догадка), потому что C # статически типизирован иподдерживает наследование от классов, определенных в скомпилированных библиотеках, что, когда у вас есть класс Sub, наследующий от класса Base, внутри экземпляра Sub действительно есть полный экземпляр Base, который вы можете получить, а затемвызовите методы на.Это повлияет на затененные поля;Я ожидал (опять же, как программист, не являющийся C #, немного догадываясь), что после получения экземпляра Base из экземпляра Sub любая прямая ссылка на поле , переопределенное Sub, ударитсяполе из Base, а не из Sub.

В Python, OTOH, нет базового экземпляра, и классы не могут переопределять поля.Если конструктор и методы Date и datetime.date оба ссылаются на одно и то же поле, то это только одно поле в экземпляре, которым они оба делятся.Таким образом, использование super не изменит того, к какому полю вы будете обращаться, как вы могли бы ожидать, если бы восприняли его как получение базового экземпляра.

Учитывая, что вы не используете сложную ситуацию множественного наследования,если вам нужен простой синтаксис, вы можете вызвать Date.__lt__(myObj, otherObj) напрямую, хотя это выглядит ужасно, потому что вы не можете использовать синтаксис инфиксного оператора, когда делаете это таким образом.Это менее ужасно, если вы рассматриваете обычные методы;в этом случае это возможно проще, чем использовать super.

Возьмите домой сообщение: я уверен, что super(Date, myObj) - это то, что вы хотите в этом случае.Но если вы попадаете в более сложные ситуации, вам не нужно думать о super как о способе получения «базового экземпляра», как в C #.Это понимание сбивает вас с толку, когда используется множественное наследование (что в любом случае может привести к путанице), но также когда у вас есть несколько слоев в иерархии наследования, использующих одно и то же поле.

...