Pythonによる拡張-super()Python 3とPython 2の使用


103

もともと私はこの質問をしたかったのですが、その前にすでに考えられていたことがわかりました...

周りをググる私はconfigparser拡張するこの例を見つけました。以下はPython 3で動作します。

$ python3
Python 3.2.3rc2 (default, Mar 21 2012, 06:59:51) 
[GCC 4.6.3] on linux2
>>> from configparser import  SafeConfigParser
>>> class AmritaConfigParser(SafeConfigParser):
...     def __init_(self):
...         super().__init__()
... 
>>> cfg = AmritaConfigParser()

しかし、Python 2ではできません。

>>> class AmritaConfigParser(SafeConfigParser):
...       def __init__(self):
...           super(SafeConfigParser).init()
... 
>>> cfg = AmritaConfigParser()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: must be type, not classob

次に、Pythonの新しいクラスのスタイルと古いクラスのスタイル(例:ここ)について少し読んでみました

class MyConfigParser(ConfigParser.ConfigParser):
      def Write(self, fp):
          """override the module's original write funcition"""
          ....
      def MyWrite(self, fp):
          """Define new function and inherit all others"""

しかし、私はinitを呼び出すべきではありませんか?これはPython 2では同等ですか?

 class AmritaConfigParser(ConfigParser.SafeConfigParser):
    #def __init__(self):
    #    super().__init__() # Python3 syntax, or rather, new style class syntax ...
    #
    # is this the equivalent of the above ? 
    def __init__(self):
        ConfigParser.SafeConfigParser.__init__(self)

1
あなたの例__init__()では、__init__()(Python 2または3のいずれかで)スーパークラスを呼び出すだけの場合、サブクラスでを定義する必要はありません。代わりに、スーパーを継承させるだけです。
マルティノー

役に立つリファレンス:amyboyle.ninja/Python-Inheritance
nu everest

リンクが修正された便利なリファレンス:amyboyle.ninja/Python-Inheritance
fearless_fool

回答:


155
  • super()(引数なしで)Python 3で導入されました(と共に__class__):

    super() -> same as super(__class__, self)

    これは、新しいスタイルのクラスと同等のPython 2になります。

    super(CurrentClass, self)
  • 古いスタイルのクラスでは、いつでも使用できます。

     class Classname(OldStyleParent):
        def __init__(self, *args, **kwargs):
            OldStyleParent.__init__(self, *args, **kwargs)

8
-1。この答えは私には何も明確にしませんでした。Pythonの2では、super(__class__)与えNameError: global name '__class__' is not defined、そしてsuper(self.__class__)だけでなく、誤りです。あなたはしなければならないあなたがする必要があることをお勧め第二引数としてインスタンスを提供しsuper(self.__class__, self)、それはある間違っています。場合Class2からの継承Class1Class1の通話super(self.__class__, self).__init__()Class1さんは__init__その後になる自分自身を呼び出すのインスタンスをインスタンス化するときClass2
jpmc26 2015

ポイントを明確にするために、Python 2でTypeError: super() takes at least 1 argument (0 given)呼び出そうとしたときに得られますsuper(self.__class__)(これはあまり意味がありませんが、この回答からどれだけの情報が欠けているかを示しています。)
jpmc26

3
@ jpmc26:python2 __init__()では、バインドされていないスーパーオブジェクト(super(self.__class__)引数を1つだけ使用して呼び出す)で引数なしで呼び出そうとすると、このエラーが発生します。バインドされたスーパーオブジェクトが必要なため、機能しますsuper(CurrentClass, self).__init__()。親を呼び出すときにself.__class__常に同じクラスを参照するため、使用しないでください。したがって、その親も同じことを行うと、無限ループが作成されます。
マタ2015

__class__(メンバー)Python2にも存在します
CristiFati 2018

3
@CristiFatiこれは__class__メンバーについてではなく、Python2には存在しない現在定義されているクラスを常に参照する暗黙的に作成された字句__class__クロージャについてです。
マタ

48

単一継承の場合(1つのクラスのみをサブクラス化する場合)、新しいクラスは基本クラスのメソッドを継承します。これも__init__ます。したがって、クラスで定義しない場合は、ベースから取得します。

多重継承(一度に複数のクラスをサブクラス化)を導入すると、状況は複雑になります。これは、複数の基本クラスが__init__場合、クラスは最初のクラスのみを継承するためです。

そのような場合は、super可能であれば実際に使用する必要があります。その理由を説明します。しかし、常にできるわけではありません。問題は、すべての基本クラスもそれを使用する必要があることです(およびその基本クラス-ツリー全体)。

その場合は、これも正しく機能します(Python 3では、Python 2に作り直すこともできます-も備えていますsuper)。

class A:
    def __init__(self):
        print('A')
        super().__init__()

class B:
    def __init__(self):
        print('B')
        super().__init__()

class C(A, B):
    pass

C()
#prints:
#A
#B

super独自の基本クラスがない場合でも、両方の基本クラスがどのように使用されるかに注意してください。

super行うことはある:それは(メソッド解決順序)MROの次のクラスのメソッドを呼び出します。のMRO Cは次のとおり(C, A, B, object)です。印刷できますC.__mro__して確認。

だから、からC継承__init__AsuperA.__init__のコールはB.__init__B次のAMROで)。

したがって、で何もしないことによりC、両方を呼び出すことになります。

を使用していない場合はsuper、継承を行うことになりますA.__init__(以前と同様に)が、今回は何もB.__init__必要ありません。

class A:
    def __init__(self):
        print('A')

class B:
    def __init__(self):
        print('B')

class C(A, B):
    pass

C()
#prints:
#A

それを修正するには、定義する必要があります C.__init__

class C(A, B):
    def __init__(self):
        A.__init__(self)
        B.__init__(self)

それに関する問題は、より複雑なMIツリーで__init__は、一部のクラスのメソッドが2回以上呼び出されることになるかもしれませんが、super / MROはそれらが1回だけ呼び出されることを保証します。


10
Notice how both base classes use super even though they don't have their own base classes.彼らは持っている。py3kでは、すべてのクラスがオブジェクトをサブクラス化します。
akaRem

これは私が探していた答えですが、尋ねる方法がわかりませんでした。MROの説明は適切です。
dturvene

27

つまり、これらは同等です。履歴ビューを見てみましょう:

(1)最初は、関数は次のようになります。

    class MySubClass(MySuperClass):
        def __init__(self):
            MySuperClass.__init__(self)

(2)コードをより抽象化する(そして移植性を高める)。スーパークラスを取得する一般的な方法は、次のように発明されています。

    super(<class>, <instance>)

そして、init関数は次のようになります。

    class MySubClassBetter(MySuperClass):
        def __init__(self):
            super(MySubClassBetter, self).__init__()

ただし、クラスとインスタンスの両方を明示的に渡す必要があると、DRY(Do n't Repeat Yourself)ルールが少し破られます。

(3)V3。よりスマートです

    super()

ほとんどの場合十分です。http://www.python.org/dev/peps/pep-3135/を参照できます。


22

Python 3の単純で完全な例を示すために、ほとんどの人が現在使用しているようです。

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

class MySub(MySuper):
    def __init__(self,a,b):
        self.b = b
        super().__init__(a)

my_sub = MySub(42,'chickenman')
print(my_sub.a)
print(my_sub.b)

与える

42
chickenman

3

super()での抽象クラスの使用を含む別のpython3実装。あなたはそれを覚えておくべきです

super().__init__(name, 10)

と同じ効果があります

Person.__init__(self, name, 10)

super()には非表示の「自己」があることを思い出してください。同じオブジェクトがスーパークラスのinitメソッドに渡され、それを呼び出したオブジェクトに属性が追加されます。したがってsuper()、翻訳さ Personれ、非表示の自己を含めると、上記のコードフラグが取得されます。

from abc import ABCMeta, abstractmethod
class Person(metaclass=ABCMeta):
    name = ""
    age = 0

    def __init__(self, personName, personAge):
        self.name = personName
        self.age = personAge

    @abstractmethod
    def showName(self):
        pass

    @abstractmethod
    def showAge(self):
        pass


class Man(Person):

    def __init__(self, name, height):
        self.height = height
        # Person.__init__(self, name, 10)
        super().__init__(name, 10)  # same as Person.__init__(self, name, 10)
        # basically used to call the superclass init . This is used incase you want to call subclass init
        # and then also call superclass's init.
        # Since there's a hidden self in the super's parameters, when it's is called,
        # the superclasses attributes are a part of the same object that was sent out in the super() method

    def showIdentity(self):
        return self.name, self.age, self.height

    def showName(self):
        pass

    def showAge(self):
        pass


a = Man("piyush", "179")
print(a.showIdentity())
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.