web-dev-qa-db-ja.com

pythonの__init__の継承とオーバーライド

私は「Dive Into Python」を読んでいて、クラスの章でこの例を挙げています:

class FileInfo(UserDict):
    "store file metadata"
    def __init__(self, filename=None):
        UserDict.__init__(self)
        self["name"] = filename

その後、著者は、__init__メソッドをオーバーライドする場合は、正しいパラメーターを使用して親__init__を明示的に呼び出す必要があると言います。

  1. そのFileInfoクラスに複数の祖先クラスがあった場合はどうなりますか?
    • すべての祖先クラスの__init__メソッドを明示的に呼び出す必要がありますか?
  2. また、オーバーライドしたい他のメソッドに対してこれを行う必要がありますか?
120
liewl

この本は、サブクラスとスーパークラスの呼び出しに関して少し古くなっています。また、サブクラスの組み込みクラスに関しては少し古いです。

最近はこんな感じです。

class FileInfo(dict):
    """store file metadata"""
    def __init__(self, filename=None):
        super( FileInfo, self ).__init__()
        self["name"] = filename

以下に注意してください。

  1. dictlistTupleなどの組み込みクラスを直接サブクラス化できます。

  2. super関数は、このクラスのスーパークラスを追跡し、それらの関数を適切に呼び出します。

147
S.Lott

継承する必要のある各クラスで、子クラスの開始時にinit'dを必要とする各クラスのループを実行できます...コピーできる例の方が理解しやすいかもしれません...

class Female_Grandparent:
    def __init__(self):
        self.grandma_name = 'Grandma'

class Male_Grandparent:
    def __init__(self):
        self.grandpa_name = 'Grandpa'

class Parent(Female_Grandparent, Male_Grandparent):
    def __init__(self):
        Female_Grandparent.__init__(self)
        Male_Grandparent.__init__(self)

        self.parent_name = 'Parent Class'

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)
#---------------------------------------------------------------------------------------#
        for cls in Parent.__bases__: # This block grabs the classes of the child
             cls.__init__(self)      # class (which is named 'Parent' in this case), 
                                     # and iterates through them, initiating each one.
                                     # The result is that each parent, of each child,
                                     # is automatically handled upon initiation of the 
                                     # dependent class. WOOT WOOT! :D
#---------------------------------------------------------------------------------------#



g = Female_Grandparent()
print g.grandma_name

p = Parent()
print p.grandma_name

child = Child()

print child.grandma_name
16
Code Bug

基本クラスの__init__メソッドを呼び出すのは実際にはhaveではありませんが、基本クラスが行うので通常はwantします残りのクラスメソッドが機能するために必要ないくつかの重要な初期化。

他の方法については、あなたの意図に依存します。基本クラスの動作に何かを追加するだけの場合は、独自のコードに追加して基本クラスメソッドを呼び出します。動作を根本的に変更する場合は、基本クラスのメソッドを呼び出して、派生クラスにすべての機能を直接実装しないでください。

14
sth

FileInfoクラスに複数の祖先クラスがある場合、それらの__init __()関数をすべて呼び出す必要があります。デストラクタである__del __()関数についても同じことを行う必要があります。

4
marcog

はい、親クラスごとに__init__を呼び出す必要があります。両方の親に存在する関数をオーバーライドする場合は、関数についても同じことが言えます。

2
vezult