web-dev-qa-db-ja.com

__init__を使用した属性の継承

私はJava Pythonの学習を始めたばかりの人です。この例を見てください:

class Person():
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone

class Teenager(Person):
    def __init__(self, name, phone, website):
        self.name=name
        self.phone=phone
        self.website=website

冗長なコードがたくさんあると確信しています(Javaの場合、上記のコードには多くの冗長性があることを知っています)。

どの属性が親クラスから既に継承されているかに関して、どの部分が冗長ですか?

39
user1111042

Pythonでクラスの___init___関数を記述する場合、そのスーパークラスの___init___関数を常に呼び出す必要があります。これを使用して、関連する属性をスーパークラスに直接渡すことができるため、コードは次のようになります。

_class Person(object):
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone
class Teenager(Person):
    def __init__(self, name, phone, website):
        Person.__init__(self, name, phone)
        self.website=website
_

他の人が指摘したように、行を置き換えることができます

_Person.__init__(self, name, phone)
_

_super(Teenager, self).__init__(name, phone)
_

コードは同じことを行います。これは、python instance.method(args)Class.method(instance, args)の略記であるためです。superを使用する場合は、コードで行ったように、objectの基本クラスとしてPersonを指定します。

python documentation には、superキーワードの使用方法に関する詳細があります。この場合の重要なことは、selfではないTeenagerのスーパークラスで___init___メソッドを探すようにpythonに指示することです。

46
murgatroid99

私がこれをしたいのは少しきれいな方法です:

class Teenager(Person):
        def __init__(self, *args, **kwargs):
           self.website=kwargs.pop('website')
           super(Teenager, self).__init__(*args, **kwargs)

この場合、大きな違いはありませんが、__init__多数の引数を使用すると、作業が楽になります。

15
Tom

Pythonの属性は、コンストラクタで定義されている場合は継承されず、親クラスのコンストラクタは手動ですべて実行しない限り呼び出されません。

class Person():
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone
class Teenager(Person):
    def_init_(self, name, phone, website):
        Person.__init__(self, name, phone)  # Call parent class constructor.
        self.website=website

詳細はこちら: http://docs.python.org/tutorial/classes.html#inheritance

6
Mischa Arefiev

これまでの例はすべて、Python 2.xに対するものでしたが、ここではPython 3.xのsuper )およびオブジェクトから継承しません。

class Person:
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone

class Teenager(Person):
    def __init__(self, name, phone, website):
        super().__init__(name, phone)
        self.website = website
5
Michael Kiros

___init___は、Javaコンストラクターとは異なり、継承階層内のすべてのクラスに対して自動的に呼び出されるわけではありません。自分で行う必要があります。

さらに、すべてのオブジェクト階層はobjectをルートにする必要があります(特別な場合を除く)。

コードは次のようになります。

_class Person(object):
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone
class Teenager(Person):
    def_init_(self, name, phone, website):
        super(Teenager, self).__init__(name, phone)
        self.website=website
_

superは、2番目の引数(self)のデリゲートを作成します。このデリゲートは、関数のリスト内の次の関数を呼び出して、各名前(「メソッド解決順序」)を呼び出します。これは、Javaで発生するスーパークラスメソッドの呼び出しとはまったく異なります。

super(type(self), self).__init__(name, phone)を書くこともできますが、このクラスからさらに継承する場合、type(self)Teenagerにならない可能性があり、無限に再帰する可能性があります。これは、スーパークラスコンストラクターを直接呼び出すのではなく、異なるMROでデリゲートオブジェクトを操作しているという事実の1つの実用的な結果です。

1
Marcin