web-dev-qa-db-ja.com

Python class inheritance:AttributeError: '[SubClass]' object has no attribute 'xxx'

次の基本クラスとサブクラスがあります。

class Event(object):
    def __init__(self, sr1=None, foobar=None):
        self.sr1 = sr1
        self.foobar = foobar
        self.state = STATE_NON_EVENT

# Event class wrappers to provide syntatic sugar
class TypeTwoEvent(Event):
    def __init__(self, level=None):
        self.sr1 = level
        self.state = STATE_EVENT_TWO

さらに私のコードで、私はTypeTwoEventクラスのインスタンスを検査して、基本クラスに存在することがわかっているフィールドをチェックしています-デフォルトで値Noneになると思っていました。ただし、私のコードでは次の例外が発生します。

AttributeError: 'TypeTwoEvent'オブジェクトに属性 'foobar'がありません

基本クラスのフィールドはサブクラスによって継承され、サブクラスのインスタンスを作成すると基本クラスがインスタンス化される(つまり、そのコンストラクターが呼び出される)という印象を受けました...

ここで何が欠けていますか? TypeTwoEventfoobar属性がないのはなぜですか-派生元の基本クラスにfoobar属性がある場合

22

サブクラスは次のようになります。

class TypeTwoEvent(Event):

    def __init__(self, level=None, *args, **kwargs):
        super(TypeTwoEvent, self).__init__(*args, **kwargs)
        self.sr1 = level
        self.state = STATE_EVENT_TWO

__init__メソッドをオーバーライドするため、親の動作を実行する場合は親メソッドを呼び出す必要があります。

__init__は、その奇妙な名前に反して特別な方法ではないことを覚えておいてください。これは、オブジェクトの作成後に自動的に呼び出されるメソッドです。それ以外の場合は通常のメソッドであり、通常の継承ルールが適用されます。

super(ClassName, self).__init__(arguments, that, goes, to, parents)

メソッドの親バージョンを呼び出す構文です。

*args**kwargsの場合、子メソッドのシグネチャがそれを行わず、親が必要とするため、__init__に渡されるすべての追加の引数をキャッチし、それを親メソッドに渡すことが保証されます。これらの引数は機能します。

24
e-satis

親クラスのコンストラクター(___init___)をオーバーライドしています。それを拡張するには、親のコンストラクタを super() 呼び出しで明示的に呼び出す必要があります。

_class TypeTwoEvent(Event):
    def __init__(self, level=None, **kwargs):
        # the super call to set the attributes in the parent class
        super(TypeTwoEvent, self).__init__(**kwargs)
        # now, extend other attributes
        self.sr1 = level
        self.state = STATE_EVENT_TWO
_

super呼び出しは常にサブクラスの___init___メソッドの先頭にあるnotであることに注意してください。その場所は、状況とロジックによって異なります。

3

インスタンスが作成されると、その__init__メソッドが呼び出されます。この場合、それはTypeTwoEvent.__init__です。スーパークラスメソッドは、非常に混乱するため、自動的には呼び出されません。

TypeTwoEvent.__init__からEvent.__init__(self, ...)を呼び出す必要があります(またはsuperを使用しますが、慣れていない場合は、最初に読んで、何をしているのかを理解してください)。

2
Chris Morgan

継承されたクラスの__init__メソッドから基本クラスの__init__メソッドを呼び出す必要があります。

これを行う方法については here を参照してください。

1
alan

私もこれに問題がありましたが、派生クラスの下部にsuper().__init__()を置いたので、機能しません。初期化されていない属性を使用しようとするためです。

0
М.Б.