복붙노트

[PYTHON] 동일한 메소드 이름을 가진 다른 경로의 Python 다중 상속

PYTHON

동일한 메소드 이름을 가진 다른 경로의 Python 다중 상속

다음 코드 샘플을 사용하면 super를 사용할 수 있습니까? 아니면 C가 A.foo 및 B.foo를 명시 적으로 호출해야합니까?

class A(object):
    def foo(self):
        print 'A.foo()'

class B(object):
    def foo(self):
        print 'B.foo()'

class C(A, B):
    def foo(self):
        print 'C.foo()'
        A.foo(self)
        B.foo(self)

해결법

  1. ==============================

    1.super ()는 주어진 메소드에 대해 하나의 클래스 유형만을 해석하므로, 여러 클래스에서 상속하고 두 메소드 모두에서 메소드를 호출하려는 경우 명시 적으로 수행해야합니다.

    super ()는 주어진 메소드에 대해 하나의 클래스 유형만을 해석하므로, 여러 클래스에서 상속하고 두 메소드 모두에서 메소드를 호출하려는 경우 명시 적으로 수행해야합니다.

  2. ==============================

    2.super는 실제로이 상황을 위해 고안된 것이지만 일관되게 사용하는 경우에만 작동합니다. 기본 클래스가 모두 super를 사용하지 않는다면 작동하지 않을 것이고, 메소드가 객체에 있지 않으면 슈퍼 클래스 체인을 종료하기 위해 공통 기본 클래스와 같은 것을 사용해야합니다.

    super는 실제로이 상황을 위해 고안된 것이지만 일관되게 사용하는 경우에만 작동합니다. 기본 클래스가 모두 super를 사용하지 않는다면 작동하지 않을 것이고, 메소드가 객체에 있지 않으면 슈퍼 클래스 체인을 종료하기 위해 공통 기본 클래스와 같은 것을 사용해야합니다.

    class FooBase(object):
        def foo(self): pass
    
    class A(FooBase):
        def foo(self):
            super(A, self).foo()
            print 'A.foo()'
    
    class B(FooBase):
        def foo(self):
            super(B, self).foo()
            print 'B.foo()'
    
    class C(A, B):
        def foo(self):
            super(C, self).foo()
            print 'C.foo()'
    

    @Marcin은 공통 기반이 있어야하는 이유를 묻습니다.

    foo를 구현하지만 super ()를 호출하지 않는 FooBase가 없으면 super ()를 호출하는 마지막 클래스는 호출 할 기본 메소드가 없으므로 속성 오류가 발생합니다.

    별도의 기본 클래스 A (AFooBase) 클래스와 B (BFooBase) 클래스가있는 경우 : A의 super () 호출은 AFooBase의 메서드를 호출하고 B의 메서드는 호출되지 않습니다. 기본 클래스가 모든 클래스에 공통적 인 경우 메서드 확인 순서가 끝나고 클래스 정의 방법에 관계없이 기본 클래스 메서드가 마지막으로 호출됩니다.

  3. ==============================

    3.이 스레드에 기여한 모든 분들께 감사드립니다.

    이 스레드에 기여한 모든 분들께 감사드립니다.

    요약하면 전체 클래스 패밀리에서 super (...)를 일관성있게 사용하면 MRO 순으로 조상의 모든 동일한 이름 메서드를 한 번 호출 할 수 있습니다. 메서드가 __init __ () 일 경우이 call-ALL-ancestor (call-only-the-first-candidate) 동작보다는 개념 상 더 쉽게 받아 들일 수 있습니다 (이 블로그 게시물의 예제 참조).

    "MRO 주문을 따르십시오"라고 말하면 매우 정확하지 않을 수도 있습니다. 그것은 실제로 "손주"의 MRO를 항상 따라갑니다. 그것을 실제로 보는 것은 매혹적입니다. 다음 프로그램의 결과가 정확히 당신이 생각했던 것과 다를 수 있습니다. A (). foo ()에 의해 트리거 될 때 수퍼 (A, 자체) .name 또는 super (A, self) .foo ()가 다른 방식으로 동작하는 방식은 서로 다른 두 가지 호출 스택에서 A .__ mro__이 어떻게 동일하게 유지되는지주의를 기울이십시오. C (). foo (). 끝에 인용 된 결과를보십시오.

    class FooBase(object):
        name = "FooBase"
        def foo(self):
            print('         Base.foo() begins')
            print("         My name is: %s" % self.name)
            print("         My super's name is not available")
            print('         Base.foo() ends')
    
    class A(FooBase):
        name = "A"
        def foo(self):
            print('     A.foo() begins')
            print("     My name is: %s" % self.name)
            print("     My super's name is: %s" % super(A, self).name)
            print("     A.__mro__ is %s" % str(A.__mro__))
            super(A, self).foo()
            print('     A.foo() ends')
    
    class B(FooBase):
        name = "B"
        def foo(self):
            print('     B.foo() begins')
            print("     My name is: %s" % self.name)
            print("     My super's name is: %s" % super(B, self).name)
            print("     B.__mro__ is %s" % str(B.__mro__))
            super(B, self).foo()
            print('     B.foo() ends')
    
    class C(A, B):
        name = "C"
        def foo(self):
            print 'C.foo() begins'
            print("My name is: %s" % self.name)
            print("My super's name is: %s" % super(C, self).name)
            print(" C.__mro__ is %s" % str(C.__mro__))
            super(C, self).foo()
            print('C.foo() ends')
    
    
    print("We will call A.foo()")
    A().foo()
    
    print("We will call C.foo()")
    C().foo()  # Run this to see how each foo() is called ONLY ONCE
    

    파이썬 2.7.12의 결과는 다음과 같습니다.

    We will call A.foo()
         A.foo() begins
         My name is: A
         My super's name is: FooBase
         A.__mro__ is (<class '__main__.A'>, <class '__main__.FooBase'>, <type 'object'>)
             Base.foo() begins
             My name is: A
             My super's name is not available
             Base.foo() ends
         A.foo() ends
    We will call C.foo()
    C.foo() begins
    My name is: C
    My super's name is: A
     C.__mro__ is (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.FooBase'>, <type 'object'>)
         A.foo() begins
         My name is: C
         My super's name is: B
         A.__mro__ is (<class '__main__.A'>, <class '__main__.FooBase'>, <type 'object'>)
         B.foo() begins
         My name is: C
         My super's name is: FooBase
         B.__mro__ is (<class '__main__.B'>, <class '__main__.FooBase'>, <type 'object'>)
             Base.foo() begins
             My name is: C
             My super's name is not available
             Base.foo() ends
         B.foo() ends
         A.foo() ends
    C.foo() ends
    
  4. ==============================

    4.Super는 "첫 번째"수퍼 클래스에서 foo 메서드를 호출합니다. 이것은 C 클래스의 메서드 확인 순서 (__mro__)를 기반으로합니다.

    Super는 "첫 번째"수퍼 클래스에서 foo 메서드를 호출합니다. 이것은 C 클래스의 메서드 확인 순서 (__mro__)를 기반으로합니다.

    >>> C.__mro__
    (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)
    >>> 
    

    따라서 super (C, self) .foo ()를 호출하면 A.foo가 호출됩니다. 상속 순서를 클래스 C (B, A)로 변경하면 다음과 반대가됩니다. __mro__은 다음과 같습니다.

    >>> C.__mro__
    (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
    >>> 
    

    이 변경 후에 super (C, self) .foo ()를 호출하면 B.foo ()가 호출됩니다.

  5. ==============================

    5.다음을 추가 한 경우 :

    다음을 추가 한 경우 :

    class A(object):
        def foo(self):
            print 'A.foo()'
    
    class B(object):
        def foo(self):
            print 'B.foo()'
    
    class C(A, B):
        def foo(self):
            super(C, self).foo()
            print 'C.foo()'
            A.foo(self)
            B.foo(self)
    
    
    c = C()
    c.foo()
    

    그러면 super (C, self) .foo ()는 A.foo를 참조합니다.

    출력은 다음과 같습니다.

    A.foo()
    C.foo()
    A.foo()
    B.foo()
    

    [편집 : 추가 정보 및 링크 포함]

  6. ==============================

    6.위에서 Duncan이 말한 것처럼 super ()를 일관성있게 사용하면 특히 예측 가능한 결과를 얻을 수 있습니다.

    위에서 Duncan이 말한 것처럼 super ()를 일관성있게 사용하면 특히 예측 가능한 결과를 얻을 수 있습니다.

    다음 테스트 결과는 나에게 도움이되었습니다.

    class FooBase(object):
        def foo(self):
            print 'FooBase.foo()'
    
    class A(FooBase):
        def foo(self):
            print 'A.foo() before super()'
            super(A, self).foo()
            print 'A.foo() after super()'
    
    class B(FooBase):
        def foo(self):
            print 'B.foo() before super()'
            super(B, self).foo()
            print 'B.foo() after super()'
    
    class C(A, B):
        def foo(self):
            print 'C.foo() before super()'
            super(C, self).foo()
            print 'C.foo() after super()'
    

    그러면 다음과 같이 인쇄됩니다.

    >>> c = C()
    >>> c.foo()
    C.foo() before super()
    A.foo() before super()
    B.foo() before super()
    FooBase.foo()
    B.foo() after super()
    A.foo() after super()
    C.foo() after super()
    
  7. ==============================

    7.슈퍼와 함께 가능합니다.

    슈퍼와 함께 가능합니다.

    class A(object):
        def foo(self):
            print 'A.foo()'
    
    class B(object):
        def foo(self):
            print 'B.foo()'
    
    class C(A, B):
        def foo(self):
            print 'C.foo()'
            super(C, self).foo() # calls A.foo()
            super(A, self).foo() # calls B.foo()
    
  8. from https://stackoverflow.com/questions/3810410/python-multiple-inheritance-from-different-paths-with-same-method-name by cc-by-sa and MIT license