60

サブクラスで上書きしたいプロパティ(getメソッド)を持つ基本クラスがあります。私の最初の考えは次のようなものでした:

class Foo(object):
    def _get_age(self):
        return 11

    age = property(_get_age)


class Bar(Foo):
    def _get_age(self):
        return 44

これは機能しません (サブクラス bar.age は 11 を返します)。機能するラムダ式を使用したソリューションを見つけました:

age = property(lambda self: self._get_age())

これは、プロパティを使用してサブクラスで上書きするための正しい解決策ですか、それともこれを行うための他の推奨される方法はありますか?

4

11 に答える 11

69

クラスメソッドをオーバーライドするときにデコレータproperty()を繰り返すのと同じように、私は単純に を繰り返すことを好みます。@classmethod

これは非常に冗長に見えますが、少なくとも Python 標準では、次のことに気付くかもしれません。

1) 読み取り専用プロパティの場合property、デコレータとして使用できます:

class Foo(object):
    @property
    def age(self):
        return 11

class Bar(Foo):
    @property
    def age(self):
        return 44

2) Python 2.6 では、プロパティはメソッドのペアを setter拡張deleterし、一般的なプロパティに適用するために使用できます。ショートカットは、読み取り専用のもので既に利用可能です:

class C(object):
    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value
于 2008-10-26T10:50:15.660 に答える
19

選択した答えが、プロパティ メソッドのオーバーライドを許可する理想的な方法であることに同意しません。ゲッターとセッターがオーバーライドされることが予想される場合は、ラムダを使用して、のようなもので自己へのアクセスを提供できますlambda self: self.<property func>

これは (少なくとも) Python バージョン 2.4 から 3.6 で動作します。

プロパティを直接の property() 呼び出しとしてではなく、デコレータとして使用する方法を誰かが知っている場合は、それを聞きたいです!

例:

class Foo(object):
    def _get_meow(self):
        return self._meow + ' from a Foo'
    def _set_meow(self, value):
        self._meow = value
    meow = property(fget=lambda self: self._get_meow(),
                    fset=lambda self, value: self._set_meow(value))

このようにして、オーバーライドを簡単に実行できます。

class Bar(Foo):
    def _get_meow(self):
        return super(Bar, self)._get_meow() + ', altered by a Bar'

となることによって:

>>> foo = Foo()
>>> bar = Bar()
>>> foo.meow, bar.meow = "meow", "meow"
>>> foo.meow
"meow from a Foo"
>>> bar.meow
"meow from a Foo, altered by a Bar"

私はこれをgeek at playで発見しました。

于 2013-01-16T00:55:18.477 に答える
12

追加のクラスを作成することなく、それを行う別の方法。2 つのうちの 1 つだけをオーバーライドした場合の動作を示す set メソッドを追加しました。

class Foo(object):
    def _get_age(self):
        return 11

    def _set_age(self, age):
        self._age = age

    age = property(_get_age, _set_age)


class Bar(Foo):
    def _get_age(self):
        return 44

    age = property(_get_age, Foo._set_age)

これはかなり不自然な例ですが、アイデアを得る必要があります。

于 2008-11-14T22:52:52.063 に答える
7

はい、これがその方法です。プロパティ宣言は、親クラスの定義が実行されるときに実行されます。つまり、親クラスに存在するメソッドのバージョンのみを「見る」ことができます。したがって、子クラスでこれらのメソッドの 1 つ以上を再定義する場合は、メソッドの子クラスのバージョンを使用してプロパティを再宣言する必要があります。

于 2008-10-26T03:07:11.727 に答える
3

可能な回避策は次のようになります。

class Foo:
    def __init__(self, age):
        self.age = age

    @property
    def age(self):
        print('Foo: getting age')
        return self._age

    @age.setter
    def age(self, value):
        print('Foo: setting age')
        self._age = value


class Bar(Foo):
    def __init__(self, age):
        self.age = age

    @property
    def age(self):
        return super().age

    @age.setter
    def age(self, value):
        super(Bar, Bar).age.__set__(self, value)

if __name__ == '__main__':
    f = Foo(11)
    print(f.age)
    b = Bar(44)
    print(b.age)

印刷します

Foo: setting age
Foo: getting age
11
Foo: setting age
Foo: getting age
44

David Beazley と Brian K. Jones による「Python Cookbook」からアイデアを得ました。Debian GNU/Linux 9.11 (ストレッチ) で Python 3.5.3 を使用する

于 2020-01-04T19:45:14.097 に答える
2

オンザフライのテンプレート方法のように見えるあなたのソリューションに同意します。 この記事では、あなたの問題を扱い、正確な解決策を提供します。

于 2008-10-26T03:01:04.127 に答える
2

このようなものが機能します

class HackedProperty(object):
    def __init__(self, f):
        self.f = f
    def __get__(self, inst, owner):    
        return getattr(inst, self.f.__name__)()

class Foo(object):
    def _get_age(self):
        return 11
    age = HackedProperty(_get_age)

class Bar(Foo):
    def _get_age(self):
        return 44

print Bar().age
print Foo().age
于 2008-10-26T03:17:07.573 に答える
2

@mr-bと同じですが、デコレータがあります。

class Foo(object):
    def _get_meow(self):
        return self._meow + ' from a Foo'
    def _set_meow(self, value):
        self._meow = value
    @property
    def meow(self):
        return self._get_meow()
    @meow.setter
    def meow(self, value):
        self._set_meow(value)

このようにして、オーバーライドを簡単に実行できます。

class Bar(Foo):
    def _get_meow(self):
        return super(Bar, self)._get_meow() + ', altered by a Bar'
于 2016-05-20T21:11:55.917 に答える
0

子クラスから親クラスのプロパティを設定する際に問題が発生しました。次の回避策は、親のプロパティを拡張しますが、親の _set_age メソッドを直接呼び出すことによって行います。しわは常に正しいはずです。ただし、少し Javathonic です。

import threading


class Foo(object):
    def __init__(self):
        self._age = 0

    def _get_age(self):
        return self._age

    def _set_age(self, age):
        self._age = age

    age = property(_get_age, _set_age)


class ThreadsafeFoo(Foo):

    def __init__(self):
        super(ThreadsafeFoo, self).__init__()
        self.__lock = threading.Lock()
        self.wrinkled = False

    def _get_age(self):
        with self.__lock:
             return super(ThreadsafeFoo, self).age

    def _set_age(self, value):
        with self.__lock:
            self.wrinkled = True if value > 40 else False
            super(ThreadsafeFoo, self)._set_age(value)

    age = property(_get_age, _set_age)
于 2015-06-02T15:52:52.433 に答える
-1
class Foo:
    # Template method
    @property
    def age(self):
        return self.dothis()
    # Hook method of TM is accessor method of property at here
    def dothis(self):
        return 11
class Bar(Foo):
    def dothis(self):
        return 44

Nizam Mohamed と同じですが、テンプレート メソッドとプロパティの両方を使用するスタイル ガイド2.13.4について言及するだけです。

于 2019-08-23T03:51:40.017 に答える