これに関する適切なオンライン ドキュメントはないようです。派生クラスを作成すると、基本クラスのすべての属性が自動的に含まれますか? しかし、BaseClass.__init()
他の基本クラスのメソッドに対してもそれを行う必要がありますか? BaseClass.__init__()
引数が必要ですか?基本クラスの引数がある場合__init__()
、それらは派生クラスでも使用されますか?引数を派生クラスの に明示的に設定する必要があります__init__()
か、またはBaseClass.__init__()
代わりに設定する必要がありますか?
2 に答える
__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__
のインスタンスである単一の引数が必要です。Foo
self
通常、クラスのインスタンスでメソッドを呼び出すと、クラス インスタンスが最初の引数として自動的に渡されます。クラスのインスタンスのメソッドは、バインドされたメソッドと呼ばれます。bar.do_something
は、バインドされたメソッドの例です (引数なしで呼び出されることに注意してください)。の特定のインスタンスにアタッチされていないためFoo.__init__
、バインドされていないメソッドFoo
です。そのため、最初の引数である のインスタンスをFoo
明示的に渡す必要があります。
この場合、 に渡しself
ます。これは、 のメソッドに渡されたFoo.__init__
のインスタンスです。はから継承されるため、 のインスタンスは のインスタンスでもあり、への受け渡しが許可されます。Bar
__init__
Bar
Bar
Foo
Bar
Foo
self
Foo.__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 のドキュメントを参照してください。ChildClass
BaseClass
super
BaseClass.method(self)
super
派生クラスを作成すると、基本クラスのすべての属性が自動的に含まれますか?
クラス属性、はい。インスタンス属性、いいえ (単に、クラスが作成されたときに存在しないため)、__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
、基本クラスの署名をコピーするか、他の場所から引数を指定するかは、何を達成しようとしているかによって異なります。