Как вызвать член данных базового класса, если он перезаписывается как свойство в производном классе? - PullRequest
5 голосов
/ 29 июня 2009

Этот вопрос похож на этот другой , с той разницей, что член данных в базовом классе не , заключенный в протокол дескриптора.

Другими словами, как я могу получить доступ к члену базового класса, если я заменяю его имя свойством в производном классе?

class Base(object):
    def __init__(self):
        self.foo = 5

class Derived(Base):
    def __init__(self):
        Base.__init__(self)

    @property
    def foo(self):
        return 1 + self.foo # doesn't work of course!

    @foo.setter
    def foo(self, f):
        self._foo = f

bar = Base()
print bar.foo

foobar = Derived()
print foobar.foo

Обратите внимание, что мне также нужно определить сеттер, потому что в противном случае присваивание self.foo в базовом классе не будет работать.

В целом протокол дескриптора, похоже, плохо взаимодействует с наследованием ...

Ответы [ 5 ]

9 голосов
/ 29 июня 2009

Жизнь проще, если вы используете делегирование вместо наследования. Это Питон. Вы не обязаны наследовать от Base.

class LooksLikeDerived( object ):
    def __init__( self ):
        self.base= Base()

    @property
    def foo(self):
        return 1 + self.base.foo # always works

    @foo.setter
    def foo(self, f):
        self.base.foo = f

А как насчет других методов Базы? Вы дублируете имена в LooksLikeDerived и просто.

def someMethodOfBase( self, *args, **kw ):
    return self.base.someMethodOfBase( *args **kw )

Да, он не ощущается как "СУХОЙ". Тем не менее, это предотвращает множество проблем, когда «оборачивает» некоторый класс в новую функциональность, как вы пытаетесь это сделать.

4 голосов
/ 29 июня 2009

Определение

def __init__(self):
    self.foo = 5

в Base делает foo членом (атрибутом) экземпляра , а не класса. Класс Base не знает foo, поэтому нет способа получить к нему доступ с помощью вызова super().

Это не обязательно, однако. Когда вы воплощаете

foobar = Derived()

и метод __init__() базового класса вызывают

self.foo = 5

это не приведет к созданию / перезаписи атрибута, но вместо этого вызовет установщик Derived, что означает

self.foo.fset(5)

и, следовательно, self._foo = 5. Так что если вы поставите

return 1 + self._foo

в своем геттере вы в значительной степени получаете то, что хотите. Если вам нужно значение, установленное self.foo в конструкторе Base, просто посмотрите на _foo, который был правильно установлен @foo.setter.

1 голос
/ 29 июня 2009
class Foo(object):
    def __new__(cls, *args, **kw):
        return object.__new__(cls, *args, **kw)

    def __init__(self):
        self.foo = 5

class Bar(Foo):
    def __new__(cls, *args, **kw):
        self = object.__new__(cls, *args, **kw)
        self.__foo = Foo.__new__(Foo)
        return self

    def __init__(self):
        Foo.__init__(self)

    @property
    def foo(self):
        return 1 + self.__foo.foo

    @foo.setter
    def foo(self, foo):
        self.__foo.foo = foo

bar = Bar()
bar.foo = 10
print bar.foo
0 голосов
/ 30 июня 2009

Честно говоря, здесь нужно обратить внимание на то, что вы пытаетесь закрутить свой код вокруг просто плохого дизайна. Дескрипторы свойств обрабатывают запрос атрибута 'foo', и вы хотите полностью их обойти, что просто неправильно. Вы уже заставляете Base. init назначать foobar._foo = 5, так что именно в этом месте должен искать геттер.

Класс Base (объект): def init (самостоятельно): self.foo = 5

class Derived(Base):
  def __init__(self):
    Base.__init__(self)

  @property
  def foo(self):
    return 1 + self._foo # DOES work of course!

  @foo.setter
  def foo(self, f):
    self._foo = f

bar = Base()
print bar.foo

foobar = Derived()
print foobar.foo
0 голосов
/ 29 июня 2009

если у вас есть свойство с таким же именем 'foo', оно отменяет поведение доступа с именем 'foo' Единственным выходом кажется, что вы явно установили 'foo' в dict

Кстати: я использую Python 2.5, поэтому пришлось немного изменить код

class Base(object):
    def __init__(self):
        self.foo = 5

class Derived(Base):
    def __init__(self):
        Base.__init__(self)

    def g_foo(self):
        return 1 + self.__dict__['foo'] # works now!

    def s_foo(self, f):
        self.__dict__['foo'] = f
        self._foo = f

    foo = property(g_foo, s_foo)

bar = Base()
print bar.foo

foobar = Derived()
print foobar.foo
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...