5

この質問はこの他の質問と似ていますが、基本クラスのデータ メンバーが記述子プロトコルによってラップされていないという違いがあります。

つまり、派生クラスのプロパティで名前をオーバーライドしている場合、基本クラスのメンバーにアクセスするにはどうすればよいでしょうか?

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 の割り当てが機能しません。

全体として、記述子プロトコルは継承とうまくやり取りしていないようです...

4

5 に答える 5

9

継承の代わりに委任を使用すると、作業がより簡単になります。これはパイソンです。から継承する義務はありません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

しかし、Base の他のメソッドはどうでしょうか? LooksLikeDerived名前を単純に複製します。

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

はい、「DRY」は感じません。ただし、しようとしているように、新しい機能で一部のクラスを「ラップ」するときに、多くの問題を防ぎます。

于 2009-06-29T10:41:40.373 に答える
4

定義する

def __init__(self):
    self.foo = 5

inBaseは、クラスではなくインスタンスfooのメンバー (属性) を作成します。クラスにはの知識がないため、呼び出しなどでアクセスする方法はありません。 Basefoosuper()

ただし、これは必須ではありません。インスタンス化すると

foobar = Derived()

および__init__()基本クラス呼び出しのメソッド

self.foo = 5

これにより、属性の作成/上書きは行われず、代わりにDerivedのセッターが呼び出されます。つまり、

self.foo.fset(5)

したがってself._foo = 5。だからあなたが置くなら

return 1 + self._foo

あなたのゲッターでは、あなたが望むものをほとんど手に入れます。のコンストラクタでself.foo設定された値が必要な場合は、 によって正しく設定された を見てください。Base_foo@foo.setter

于 2009-06-29T10:24:25.773 に答える
1
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
于 2009-06-29T13:13:45.073 に答える
0

同じ名前「foo」のプロパティがあると、名前「foo」のアクセスの動作がオーバーライドされます

ところで:私は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
于 2009-06-29T10:25:12.153 に答える
0

正直なところ、ここで注目すべきことは、単純に貧弱な設計に合わせてコードをひねろうとしているということです。プロパティ記述子は「foo」属性の要求を処理しますが、これらを完全にバイパスしたいのですが、これは間違っています。あなたはすでにベースを引き起こしています。initを使用して foobar._foo = 5 を割り当てます。そのため、ゲッターも正確に探す必要があります。

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 # DOES work of course!

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

bar = Base()
print bar.foo

foobar = Derived()
print foobar.foo
于 2009-06-29T23:31:53.780 に答える