子クラスから親クラスのメソッドを呼び出しますか?


608

Pythonで単純なオブジェクト階層を作成するとき、派生クラスから親クラスのメソッドを呼び出せるようにしたいと思います。PerlとJavaには、このためのキーワードがあります(super)。Perlでは、私はこれを行うかもしれません:

package Foo;

sub frotz {
    return "Bamf";
}

package Bar;
@ISA = qw(Foo);

sub frotz {
   my $str = SUPER::frotz();
   return uc($str);
}

Pythonでは、親クラスに子から明示的に名前を付ける必要があるようです。上記の例では、のようにする必要がありFoo::frotz()ます。

この動作では深い階層を作成することが困難になるため、これは正しくないようです。子供が継承されたメソッドを定義したクラスを知る必要がある場合は、あらゆる種類の情報の苦痛が生じます。

これはPythonの実際の制限ですか、私の理解のギャップですか?


3
親クラスの命名はそれほど悪い考えではないと思います。親クラスに明示的に名前を付けるため、子クラスが複数の親から継承する場合に役立ちます。

7
クラスに名前を付けるオプションは悪い考えではありませんが、そうすることを余儀なくされるのは確かです。
johndodo 2014

Python 2とPython 3の間のスーパーハンドリングの変更点https://www.python.org/dev/peps/pep-3135/に注意してください。クラスに名前を付ける必要はありません(ただし、少なくとも場合によっては、それでも神の考えかもしれません)。
jwpfox 2016

回答:


737

はい。ただし、新しいスタイルのクラスのみ。super()関数を使用します。

class Foo(Bar):
    def baz(self, arg):
        return super().baz(arg)

Python <3の場合、次を使用します。

class Foo(Bar):
    def baz(self, arg):
        return super(Foo, self).baz(arg)

53
「return Bar.baz(self、arg)」もできないの?もしそうなら、どちらが良いでしょうか?

15
はい、できますが、OPは呼び出しサイト(この場合はBar)でスーパークラスに明示的に名前を付けずにそれを行う方法を求めていました。
アダムローゼンフィールド

7
super()は多重継承で奇妙です。「次の」クラスを呼び出します。それは親クラスかもしれませんし、階層のどこかに現れるまったく無関係なクラスかもしれません。
スティーブジェソップ

6
私はPython 2.xを使用していて、これを実行すると「エラー:classobjではなくタイプである必要があります」と表示されます
Chris F

28
構文super(Foo, self)はPython 2.x用ですか?Python 3.xでは、これsuper()が正しいですか?
Trevor Boyd Smith

144

Pythonにもスーパーがあります:

super(type[, object-or-type])

タイプの親クラスまたは兄弟クラスにメソッド呼び出しを委任するプロキシオブジェクトを返します。これは、クラスでオーバーライドされた継承されたメソッドにアクセスするのに役立ちます。検索順序は、タイプ自体がスキップされることを除いて、getattr()が使用する順序と同じです。

例:

class A(object):     # deriving from 'object' declares A as a 'new-style-class'
    def foo(self):
        print "foo"

class B(A):
    def foo(self):
        super(B, self).foo()   # calls 'A.foo()'

myB = B()
myB.foo()

7
オブジェクトの基本クラスで新しいスタイルのクラスを使用することを示したので、Adamの例よりも優れています。新しいスタイルのクラスへのリンクがない。
Samuel

83
ImmediateParentClass.frotz(self)

直接の親クラスがfrotzそれ自体を定義したか、継承したかにかかわらず、問題ありません。 多重継承superを適切にサポートするためにのみ必要です(すべてのクラスが適切に使用する場合にのみ機能します)。一般的には、ルックアップするために起こっているに場合の祖先/定義をオーバーライドしない、これは、他の出現のためとして、 『親のメソッドを呼び出して子クラス』にも当てはまります!AnyClass.whateverwhateverAnyClassAnyClass


これは、ImmediateParentClassもこのステートメントが実行されるスコープ内に存在することを要求します。モジュールからオブジェクトをインポートするだけでは役に立ちません。
Tushar Vazirani

クラスメソッドの場合はどうなりますか?
Shiplu Mokaddim

@TusharVazirani親クラスが即時parentである場合、それはクラス全体のスコープ内ですよね?
Yaroslav Nikitenko

1
@YaroslavNikitenkoクラスではなく、インスタンスのインポートについて話しています。
Tushar Vazirani

1
@TusharVaziraniわかりました、ありがとう。(OPで述べられているように)現在のクラスのメソッドから呼び出すことを考えていました。
Yaroslav Nikitenko

75

Python 3には、親メソッドを呼び出すための異なる簡単な構文があります。

Fooクラスがfromを継承する場合Bar、from Bar.__init__Foovia から呼び出すことができますsuper().__init__()

class Foo(Bar):

    def __init__(self, *args, **kwargs):
        # invoke Bar.__init__
        super().__init__(*args, **kwargs)

5
Python 3の方が良い解決策があると聞いて良かった。質問はpython 2.Xから来ています。しかし提案をありがとう。
jjohn

46

多くの回答が、子でオーバーライドされた親からメソッドを呼び出す方法を説明しています。

しかしながら

「子クラスから親クラスのメソッドをどのように呼び出しますか?」

単に意味することもできます:

「継承されたメソッドをどのように呼び出しますか?」

親クラスから継承されたメソッドは、上書きされていない限り、子クラスのメソッドと同じように呼び出すことができます。

たとえばpython 3の場合:

class A():
  def bar(self, string):
    print("Hi, I'm bar, inherited from A"+string)

class B(A):
  def baz(self):
    self.bar(" - called by baz in B")

B().baz() # prints out "Hi, I'm bar, inherited from A - called by baz in B"

はい、これはかなり明白かもしれませんが、私はこれを指摘しないと、Pythonで継承されたメソッドにアクセスするためだけにとんでもないフープを飛び越えなければならないという印象でこのスレッドを離れるかもしれません。特にこの質問は「Pythonで親クラスのメソッドにアクセスする方法」の検索で高く評価され、OPはPythonを初めて使う人の観点から書かれています。

私が見つけた:https : //docs.python.org/3/tutorial/classes.html#inheritanceは 、継承されたメソッドにアクセスする方法を理解するのに役立ちます。


@gizzmoleはどのような状況で機能しないのですか?関連する警告や警告があれば喜んで追加しますが、投稿したリンクがこの回答にどのように関連しているかはわかりません。
ベン

@ベン申し訳ありませんが、私はあなたの答えを十分に読みませんでした。この答えは、関数をオーバーロードする方法に関する質問には答えませんが、別の質問に答えます。最初のコメントを削除しました。
gizzmole

@gizzmoleああ、心配ありません。この回答はオーバーロード関数には適用されないことを理解していますが、質問では明示的にオーバーロードについて言及していません(ただし、指定されたperlの例ではオーバーロードの例を示しています)。他の回答の大部分は過負荷をカバーしています-これはそれを必要としない人々のためにここにあります。
ベン

@Ben Cで定義された変数を使用して、「C」という名前の別のクラスからB()。baz()を呼び出す場合はどうなりますか?クラスCでB()。baz()を試してみましたが、self.stringは別のvalです。私が実行したとき、それは私に何も与えませんでした
joey '25

@joeyあなたが何をしようとしているのか、それがこの質問の範囲内であるかどうかはわかりません。文字列はローカル変数です-設定self.stringは何もしません。ただし、クラスCでは、電話をかけることはできますB().bar(string)
Ben

27

これがsuper()の使用例です。

#New-style classes inherit from object, or from another new-style class
class Dog(object):

    name = ''
    moves = []

    def __init__(self, name):
        self.name = name

    def moves_setup(self):
        self.moves.append('walk')
        self.moves.append('run')

    def get_moves(self):
        return self.moves

class Superdog(Dog):

    #Let's try to append new fly ability to our Superdog
    def moves_setup(self):
        #Set default moves by calling method of parent class
        super(Superdog, self).moves_setup()
        self.moves.append('fly')

dog = Superdog('Freddy')
print dog.name # Freddy
dog.moves_setup()
print dog.get_moves() # ['walk', 'run', 'fly']. 
#As you can see our Superdog has all moves defined in the base Dog class

これは悪い例ではありませんか?私はあなたの全体の階層がスーパー()を呼び出し、「新しいスタイル」クラスと適切でない限り、それはスーパーを使用するために本当に安全ではありません信じているのinit()。
Jaykul

14

Pythonにもsuper()があります。Pythonの古いスタイルと新しいスタイルのクラスのため、これは少し不安定ですが、たとえばコンストラクターで非常に一般的に使用されています。

class Foo(Bar):
    def __init__(self):
        super(Foo, self).__init__()
        self.baz = 5

10

CLASS.__bases__ このようなものを使用することをお勧めします

class A:
   def __init__(self):
        print "I am Class %s"%self.__class__.__name__
        for parentClass in self.__class__.__bases__:
              print "   I am inherited from:",parentClass.__name__
              #parentClass.foo(self) <- call parents function with self as first param
class B(A):pass
class C(B):pass
a,b,c = A(),B(),C()

1
ここでのsuperへの参照の量からわかるように、本当に深いことをしているのでない限り、人々は基本を使うのが嫌いだということ覚えておいてください。スーパーが気に入らなければ、mroを見てくださいmroの最初のエントリを取得する方が、拠点のどのエントリを使用するかを追跡するよりも安全です。Pythonの多重継承は、特定のものを逆方向にスキャンし、他のものを順方向にスキャンするため、言語がプロセスをほどくのが最も安全です。
Jon Jay Obermark 2014


5

Pythonにもsuper()があります。

スーパークラスメソッドがサブクラスメソッドから呼び出される方法の例

class Dog(object):
    name = ''
    moves = []

    def __init__(self, name):
        self.name = name

    def moves_setup(self,x):
        self.moves.append('walk')
        self.moves.append('run')
        self.moves.append(x)
    def get_moves(self):
        return self.moves

class Superdog(Dog):

    #Let's try to append new fly ability to our Superdog
    def moves_setup(self):
        #Set default moves by calling method of parent class
        super().moves_setup("hello world")
        self.moves.append('fly')
dog = Superdog('Freddy')
print (dog.name)
dog.moves_setup()
print (dog.get_moves()) 

この例は、上記で説明したものと似ていますが、superに引数が渡されないという違いが1つあります。この上記のコードは、Python 3.4バージョンで実行可能です。


3

この例でcafec_paramは、基本クラス(親クラス)でabcあり、子クラスです。基本クラスのメソッドをabc呼び出しますAWC

class cafec_param:

    def __init__(self,precip,pe,awc,nmonths):

        self.precip = precip
        self.pe = pe
        self.awc = awc
        self.nmonths = nmonths

    def AWC(self):

        if self.awc<254:
            Ss = self.awc
            Su = 0
            self.Ss=Ss
        else:
            Ss = 254; Su = self.awc-254
            self.Ss=Ss + Su   
        AWC = Ss + Su
        return self.Ss


    def test(self):
        return self.Ss
        #return self.Ss*4

class abc(cafec_param):
    def rr(self):
        return self.AWC()


ee=cafec_param('re',34,56,2)
dd=abc('re',34,56,2)
print(dd.rr())
print(ee.AWC())
print(ee.test())

出力

56

56

56

2

Python 2では、super()にはあまり運がありませんでした。私はこのSOスレッドでjimifikiからの回答を使用して、pythonで親メソッドを参照する方法を教えてください?。次に、独自の小さなひねりを加えました。これは使いやすさの向上だと思います(特に、クラス名が長い場合)。

1つのモジュールで基本クラスを定義します。

 # myA.py

class A():     
    def foo( self ):
        print "foo"

次に、クラスを別のモジュールにインポートしますas parent

# myB.py

from myA import A as parent

class B( parent ):
    def foo( self ):
        parent.foo( self )   # calls 'A.foo()'

2
Thenのclass A(object): 代わり に使用する必要があります class A():super()が機能します
blndev

私がフォローしているのかわかりません。クラスの定義を意味しますか?明らかに、親を参照できると考えるためには、クラスが親を持っていることを何らかの方法で示す必要があります。9か月前に投稿したので、詳細については少しあいまいですが、Arun Ghosh、lawrence、kkkなどの例はPy 2.xには適用されないことを意味していると思います。代わりに、機能するメソッドと親を参照する簡単な方法を以下に示します。(スーパーを使用するのと同じように)
BuvinJ

0
class department:
    campus_name="attock"
    def printer(self):
        print(self.campus_name)

class CS_dept(department):
    def overr_CS(self):
        department.printer(self)
        print("i am child class1")

c=CS_dept()
c.overr_CS()

-3
class a(object):
    def my_hello(self):
        print "hello ravi"

class b(a):
    def my_hello(self):
    super(b,self).my_hello()
    print "hi"

obj = b()
obj.my_hello()

2
Stackoverflowへようこそ。この質問は、ほぼ10年前に既に詳細に回答されており、その回答は受け入れられ、大部分が賛成されました。そして、あなたの回答は何も新しいものを追加しません。代わりに、最近の(できれば未回答の)質問に答えてみてください。補足として、適切なコードのフォーマットを適用するためのボタンがエディターにあります。
Bruno desthuilliers

-24

これはより抽象的な方法です:

super(self.__class__,self).baz(arg)

15
self .__ class__は、selfは常にインスタンスであり、そのクラスは常にインスタンスのクラスであるため、superでは正しく機能しません。この手段は、スーパー使用する場合(自己.__ class__は...そのクラスがから継承されたクラスでは、それはもう動作しません。
xitrium

16
強調するために、このコードは使用しないでください。これは、MROを正しくトラバースするというsuper()の目的全体を無効にします。
Eevee、2012

1
stackoverflow.com/a/19257335/419348は、なぜ電話しないのかと述べましたsuper(self.__class__, self).baz(arg)
AechoLiu 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.