26

これに関する適切なオンライン ドキュメントはないようです。派生クラスを作成すると、基本クラスのすべての属性が自動的に含まれますか? しかし、BaseClass.__init()他の基本クラスのメソッドに対してもそれを行う必要がありますか? BaseClass.__init__()引数が必要ですか?基本クラスの引数がある場合__init__()、それらは派生クラスでも使用されますか?引数を派生クラスの に明示的に設定する必要があります__init__()か、またはBaseClass.__init__()代わりに設定する必要がありますか?

4

2 に答える 2

62

__init__BaseClass から派生したクラスで実装すると、継承された__init__メソッドが上書きされるため、BaseClass.__init__呼び出されることはありません。BaseClassのメソッドを呼び出す必要が__init__ある場合 (通常はそうです)、それを行うのはあなた次第でありBaseClass.__init__、通常は新しく実装された__init__メソッド内から を呼び出すことによって明示的に行われます。

class Foo(object):
    def __init__(self):
        self.a = 10

    def do_something(self):
        print self.a

class Bar(Foo):
    def __init__(self):
        self.b = 20

bar = Bar()
bar.do_something()

これにより、次のエラーが発生します。

AttributeError: 'Bar' object has no attribute 'a'

したがって、do_somethingメソッドは期待どおりに継承されましたが、そのメソッドには属性が設定されている必要があり、これも上書きされaたため、決してそうではありません。__init__内部から明示的に呼び出すことで、これを回避Foo.__init__しますBar.__init__

class Foo(object):
    def __init__(self):
        self.a = 10

    def do_something(self):
        print self.a

class Bar(Foo):
    def __init__(self):
        Foo.__init__(self)
        self.b = 20

bar = Bar()
bar.do_something()

期待どおりに印刷10されます。この場合、 (慣例により と呼ばれる)Foo.__init__のインスタンスである単一の引数が必要です。Fooself

通常、クラスのインスタンスでメソッドを呼び出すと、クラス インスタンスが最初の引数として自動的に渡されます。クラスのインスタンスのメソッドは、バインドされたメソッドと呼ばれます。bar.do_somethingは、バインドされたメソッドの例です (引数なしで呼び出されることに注意してください)。の特定のインスタンスにアタッチされていないためFoo.__init__バインドされていないメソッドFooです。そのため、最初の引数である のインスタンスをFoo明示的に渡す必要があります。

この場合、 に渡しselfます。これは、 のメソッドに渡されたFoo.__init__のインスタンスです。はから継承されるため、 のインスタンスは のインスタンスでもあり、への受け渡しが許可されます。Bar__init__BarBarFooBarFooselfFoo.__init__

継承元のクラスが、クラスのインスタンスだけでなく、より多くの引数を必要とするか受け入れる場合があります。これらは、 内から呼び出しているメソッドと同じように処理されます__init__

class Foo(object):
    def __init__(self, a=10):
        self.a = a

    def do_something(self):
        print self.a

class Bar(Foo):
    def __init__(self):
        Foo.__init__(self, 20)

bar = Bar()
bar.do_something()

これは印刷されます20

継承クラスを介して基本クラスのすべての初期化引数を完全に公開するインターフェイスを実装しようとしている場合は、明示的に行う必要があります。これは通常、明示的に名前が付けられていない残りのすべての引数のプレースホルダーである *args および **kwargs 引数 (名前は慣例による) で行われます。次の例では、これまでに説明したすべてを利用しています。

class Foo(object):
    def __init__(self, a, b=10):
        self.num = a * b

    def do_something(self):
        print self.num

class Bar(Foo):
    def __init__(self, c=20, *args, **kwargs):
        Foo.__init__(self, *args, **kwargs)
        self.c = c

    def do_something(self):
        Foo.do_something(self)
        print self.c


bar = Bar(40, a=15)
bar.do_something()

この場合、引数cは の最初の引数であるため、40 に設定されますBar.__init__args次に、2 番目の引数が変数andに組み込まれkwargs(* と ** は、関数/メソッドに渡すときに、リスト/タプルまたは辞書を個別の引数に展開することを示す特定の構文です)、 に渡されFoo.__init__ます。

この例では、 (この場合のように) 必要な場合は、上書きされたメソッドを明示的に呼び出す必要があることdo_something指摘しています。

最後に、メソッドを明示的に呼び出す代わりにsuper(ChildClass, self).method()(どこに任意の子クラスがあるか) が使用されていることがよくあります。の議論はまったく別の質問ですが、これらの場合、通常、 を呼び出すことによって行われていることを正確に行うために使用されていると言えば十分です。簡単に言えば、メソッド呼び出しをメソッド解決順序の次のクラスである MRO (単一継承では親クラス) に委譲します。詳細については、super のドキュメントを参照してください。ChildClassBaseClasssuperBaseClass.method(self)super

于 2011-06-18T14:58:55.570 に答える
11

派生クラスを作成すると、基本クラスのすべての属性が自動的に含まれますか?

クラス属性、はい。インスタンス属性、いいえ (単に、クラスが作成されたときに存在しないため)、__init__派生クラスに存在しない場合を除きます。その場合、代わりに基本クラスが呼び出され、インスタンス属性が設定されます。

BaseClass を行います。init () 引数が必要ですか?

__init__クラスとその署名に依存します。派生クラスで明示的に呼び出す場合Base.__init__は、少なくともself最初の引数として渡す必要があります。あなたが持っている場合

class Base(object):
    def __init__(self):
        # something

その場合、他の引数が によって受け入れられないことは明らかです__init__。もしあれば

class Base(object):
    def __init__(self, argument):
        # something

argument次に、 base を呼び出すときに渡す必要があります__init__。ここにはロケット科学はありません。

基本クラスinit () の引数がある場合、それらは派生クラスでも使用されますか? 引数を派生クラスのinit () に明示的に設定する必要がありますか、それとも BaseClass に設定する必要がありますか? init () 代わりに?

繰り返しになりますが、派生クラスに がない場合は__init__、代わりに基本クラスが使用されます。

class Base(object):
    def __init__(self, foo):
        print 'Base'

class Derived(Base):
    pass

Derived()   # TypeError
Derived(42) # prints Base

それ以外の場合は、何らかの方法で処理する必要があります。引数を変更せずに基本クラスに渡すか*args, **kwargs、基本クラスの署名をコピーするか、他の場所から引数を指定するかは、何を達成しようとしているかによって異なります。

于 2011-06-18T14:02:16.137 に答える