web-dev-qa-db-ja.com

サブクラス化:従来の属性でプロパティをオーバーライドすることは可能ですか?

包括的な概念の異なる実装または特殊化であるクラスのファミリーを作成したいとしましょう。一部の派生プロパティにもっともらしいデフォルト実装があると仮定しましょう。これを基本クラスに入れたい

class Math_Set_Base:
    @property
    def size(self):
        return len(self.elements)

したがって、サブクラスは自動的にこのかなりばかげた例の要素を数えることができます

class Concrete_Math_Set(Math_Set_Base):
    def __init__(self,*elements):
        self.elements = elements

Concrete_Math_Set(1,2,3).size
# 3

しかし、サブクラスがこのデフォルトを使用したくない場合はどうなりますか?これは動作しません:

import math

class Square_Integers_Below(Math_Set_Base):
    def __init__(self,cap):
        self.size = int(math.sqrt(cap))

Square_Integers_Below(7)
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
#   File "<stdin>", line 3, in __init__
# AttributeError: can't set attribute

プロパティをプロパティでオーバーライドする方法はあると思いますが、それは避けたいです。基本クラスの目的は、ユーザーの生活をできるだけ簡単にすることであり、(サブクラスの狭い観点から)複雑で余分なアクセスメソッドを課すことによって膨張を追加することではありません。

できますか?そうでない場合、次善の策は何ですか?

21
Paul Panzer

基本クラスのプロパティを、派生クラス内の派生クラスの別のプロパティに設定し、新しい値で基本クラスのプロパティを使用することは可能だと思います。

最初のコードでは、基本クラスの名前sizeと派生クラスの属性self.sizeの間に一種の矛盾があります。これは、派生クラスの名前self.sizeself.lengthに置き換えると表示されます。これは出力します:

3
<__main__.Square_Integers_Below object at 0x000001BCD56B6080>

次に、プログラムのすべてのオカレンスでメソッドsizelengthに置き換えると、同じ例外が発生します。

Traceback (most recent call last):
  File "C:/Users/Maria/Downloads/so_1.2.py", line 24, in <module>
    Square_Integers_Below(7)
  File "C:/Users/Maria/Downloads/so_1.2.py", line 21, in __init__
    self.length = int(math.sqrt(cap))
AttributeError: can't set attribute

固定コード、またはとにかく機能するバージョンは、基本クラスからメソッドsizeを設定するクラスSquare_Integers_Belowを除いて、コードをまったく同じに保つことです。別の値に。

class Square_Integers_Below(Math_Set_Base):

    def __init__(self,cap):
        #Math_Set_Base.__init__(self)
        self.length = int(math.sqrt(cap))
        Math_Set_Base.size = self.length

    def __repr__(self):
        return str(self.size)

そして、すべてのプログラムを実行すると、出力は次のようになります。

3
2

これが何らかの形で役立つことを願っています。

1
Sofia190

また、次のことができます

class Math_Set_Base:
    _size = None

    def _size_call(self):
       return len(self.elements)

    @property
    def size(self):
        return  self._size if self._size is not None else self._size_call()

class Concrete_Math_Set(Math_Set_Base):
    def __init__(self, *elements):
        self.elements = elements


class Square_Integers_Below(Math_Set_Base):
    def __init__(self, cap):
        self._size = int(math.sqrt(cap))