super (인수 전달)를 사용하는 올바른 방법


99

그래서 저는 Python의 Super Concerned Harmful 을 따르고 그의 예제를 테스트했습니다.

그러나 다른 인수를 예상 하는 메서드를 처리 할 때 올바른 호출 방법을 보여주는 Example 1-3 은 flat-out이 작동하지 않습니다.super__init__

이것이 내가 얻는 것입니다.

~ $ python example1-3.py 
MRO: ['E', 'C', 'A', 'D', 'B', 'object']
E arg= 10
C arg= 10
A
D arg= 10
B
Traceback (most recent call last):
  File "Download/example1-3.py", line 27, in <module>
    E(arg=10)
  File "Download/example1-3.py", line 24, in __init__
    super(E, self).__init__(arg, *args, **kwargs)
  File "Download/example1-3.py", line 14, in __init__
    super(C, self).__init__(arg, *args, **kwargs)
  File "Download/example1-3.py", line 4, in __init__
    super(A, self).__init__(*args, **kwargs)
  File "Download/example1-3.py", line 19, in __init__
    super(D, self).__init__(arg, *args, **kwargs)
  File "Download/example1-3.py", line 9, in __init__
    super(B, self).__init__(*args, **kwargs)
TypeError: object.__init__() takes no parameters

object자체적으로 문서에 언급 된 모범 사례 중 하나를 위반 하는 것 같습니다. 즉 , 사용하는 메서드 super*args**kwargs.

자, 분명히 Mr. Knight는 그의 예제가 작동하기를 기대했습니다. 그렇다면 이것이 최신 버전의 Python에서 변경된 것입니까? 2.6과 2.7을 확인했는데 둘 다 실패했습니다.

그렇다면이 문제를 해결하는 올바른 방법은 무엇입니까?


2
내가 선호하는 방법은 다음과 같습니다 : 단순하고 단순한 상속 계층.
millimoose

19
또한 읽어야합니다 "슈퍼 고려 파이썬의 슈퍼 ()"를 균형보기 :) 얻을
비욘 Pollex

@ BjörnPollex : 감사합니다! 귀하의 링크는 질문에 대한 답을 제공합니다.에서 상속하는 "루트 클래스"를 작성할 수 있으며 's를 올바르게 object호출하는지 확인 합니다. object__init__
cha0site

4
참고 __init__object자동으로 무시 파이썬 2.5에 매개 변수. 이것은 Python 2.6에서 변경되었습니다.
Wilfred Hughes

1
@Wilfred : 헤이, 실제 질문에 답 해주셔서 감사합니다! 이제 에세이가 구식 인 이유를 알고 있습니다!
cha0site

답변:


103

때로는 두 클래스에 공통 매개 변수 이름이있을 수 있습니다. 이 경우 키-값 쌍을에서 **kwargs제거하거나 제거 할 수 없습니다 *args. 대신, 인수를 흡수 / 무시 하는 Base클래스를 정의 할 수 있습니다 object.

class Base(object):
    def __init__(self, *args, **kwargs): pass

class A(Base):
    def __init__(self, *args, **kwargs):
        print "A"
        super(A, self).__init__(*args, **kwargs)

class B(Base):
    def __init__(self, *args, **kwargs):
        print "B"
        super(B, self).__init__(*args, **kwargs)

class C(A):
    def __init__(self, arg, *args, **kwargs):
        print "C","arg=",arg
        super(C, self).__init__(arg, *args, **kwargs)

class D(B):
    def __init__(self, arg, *args, **kwargs):
        print "D", "arg=",arg
        super(D, self).__init__(arg, *args, **kwargs)

class E(C,D):
    def __init__(self, arg, *args, **kwargs):
        print "E", "arg=",arg
        super(E, self).__init__(arg, *args, **kwargs)

print "MRO:", [x.__name__ for x in E.__mro__]
E(10)

수확량

MRO: ['E', 'C', 'A', 'D', 'B', 'Base', 'object']
E arg= 10
C arg= 10
A
D arg= 10
B

이것이 작동 Base하려면 MRO에서 두 번째 클래스 여야합니다.


4
Base전화 super(Base, self).__init__()?
cha0site

4
이 작업을 수행 Base하려면 MRO 끝에 와야합니다 (제외 object). 호출 object.__init__은 아무 일도하지 않으므로을 호출 하지 않아도됩니다 super(Base, self).__init__(). 사실, 선의 끝인 super(Base, self).__init__()지점을 집으로 몰아 넣는 것을 포함하지 않는 것이 더 분명하다고 생각합니다 Base.
unutbu

25

많은 상속 을 받으려면 ( 여기에서 그렇습니다)를 사용하여 모든 매개 변수를 전달한 **kwargs다음 pop사용 직후 에 전달하는 것이 좋습니다 (상위 클래스에서 필요하지 않은 경우).

class First(object):
    def __init__(self, *args, **kwargs):
        self.first_arg = kwargs.pop('first_arg')
        super(First, self).__init__(*args, **kwargs)

class Second(First):
    def __init__(self, *args, **kwargs):
        self.second_arg = kwargs.pop('second_arg')
        super(Second, self).__init__(*args, **kwargs)

class Third(Second):
    def __init__(self, *args, **kwargs):
        self.third_arg = kwargs.pop('third_arg')
        super(Third, self).__init__(*args, **kwargs)

이것은 이러한 종류의 문제를 해결하는 가장 간단한 방법입니다.

third = Third(first_arg=1, second_arg=2, third_arg=3)

6

파이썬의 super () 에서 설명했듯이 super로 간주되는 한 가지 방법은 클래스가 필요한 인수를 먹고 나머지는 전달하도록하는 것입니다. 따라서 호출 체인이에 도달 object하면 모든 인수가 먹혀지고 object.__init__인수없이 (예상대로) 호출됩니다. 따라서 코드는 다음과 같아야합니다.

class A(object):
    def __init__(self, *args, **kwargs):
        print "A"
        super(A, self).__init__(*args, **kwargs)

class B(object):
    def __init__(self, *args, **kwargs):
        print "B"
        super(B, self).__init__(*args, **kwargs)

class C(A):
    def __init__(self, arg, *args, **kwargs):
        print "C","arg=",arg
        super(C, self).__init__(*args, **kwargs)

class D(B):
    def __init__(self, arg, *args, **kwargs):
        print "D", "arg=",arg
        super(D, self).__init__(*args, **kwargs)

class E(C,D):
    def __init__(self, arg, *args, **kwargs):
        print "E", "arg=",arg
        super(E, self).__init__(*args, **kwargs)

print "MRO:", [x.__name__ for x in E.__mro__]
E(10, 20, 30)

그래서 E(arg = 10)어떻습니까? 이 방법이 마음에 들지 않습니다. 사용하려면 MRO를 미리 알아야합니다. 상속 된 "루트 클래스"를 작성하는 다른 방법 object은 훨씬 더 깔끔해 보입니다.
cha0site

이 메서드는 호출 된 함수가 인수 이름을 공유하지 않는 경우에 유용합니다. 에 대한 실제 경험이 많지 않다는 것을 인정하므로이 super접근 방식은 실제로 이론적 일 수 있습니다.
Björn Pollex
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.