これに関する優れたオンラインドキュメントはないようです。派生クラスを作成すると、基本クラスのすべての属性が自動的に得られますか?しかし、BaseClass.__init()
は何のためのものですか、他の基本クラスのメソッドに対しても行う必要がありますか? BaseClass.__init__()
には引数が必要ですか?基本クラス__init__()
の引数がある場合、それらも派生クラスで使用されますか?派生クラスの__init__()
に引数を明示的に設定する必要がありますか、それともBaseClass.__init__()
?
BaseClassから派生したクラスに__init__
を実装すると、継承された__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
と呼ばれます)のインスタンスである単一の引数を予期します。
通常、クラスのインスタンスでメソッドを呼び出すと、クラスインスタンスが最初の引数として自動的に渡されます。クラスのインスタンスのメソッドは、bound methodと呼ばれます。 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
は、Bar.__init__
の最初の引数であるため、40に設定されます。次に、2番目の引数が変数args
およびkwargs
に組み込まれ(*および**は、関数/メソッドに渡すときにリスト/タプルまたはディクショナリを個別の引数に展開することを示す特定の構文です)、Foo.__init__
に渡されます。
この例は、any上書きされたメソッドが必要な場合は明示的に呼び出す必要があることも示しています(この場合、do_something
があるため)。
最後に、ChildClass
メソッドを明示的に呼び出す代わりに、super(ChildClass, self).method()
(BaseClass
は任意の子クラス)を使用することがよくあります。 super
についての議論は、まったく別の質問ですが、これらのケースでは、通常、BaseClass.method(self)
を呼び出すことによって行われていることを正確に行うために使用されています。簡単に言うと、super
は、メソッド呼び出しをメソッド解決順序の次のクラスであるMRO(単一継承では親クラス)に委譲します。詳細は superのドキュメント を参照してください。
派生クラスを作成すると、基本クラスのすべての属性が自動的に含まれますか?
クラス属性、はい。派生クラスに__init__
がない場合を除いて、インスタンス属性はありません(単にクラスが作成されたときに存在しないためです)。その場合、基本クラスが代わりに呼び出され、インスタンス属性が設定されます。
BaseClass .init()には引数が必要ですか?
クラスとその__init__
署名によって異なります。派生クラスで明示的にBase.__init__
を呼び出す場合は、少なくとも最初の引数としてself
を渡す必要があります。あなたが持っている場合
class Base(object):
def __init__(self):
# something
次に、__init__
が他の引数を受け入れないことは明らかです。あなたが持っているなら
class Base(object):
def __init__(self, argument):
# something
次に、base __init__
を呼び出すときにargument
を渡す必要があります。ここにはロケット科学はありません。
基本クラスの引数がある場合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
を使用して、引数を変更せずに基本クラスに渡すか、基本クラスの署名をコピーするか、他の場所から引数を提供するかは、達成しようとしていることに依存します。