왜 파이썬 3.x의 super ()가 마술입니까?


159

Python 3.x에서는 super()인수없이 호출 할 수 있습니다.

class A(object):
    def x(self):
         print("Hey now")

class B(A):
    def x(self):
        super().x()
>>> B().x()
Hey now

이 일을하기 위해, 일부 컴파일시의 마법은 (리 바인드 다음 코드이다 한 결과 그 중, 수행 super에가 super_) 실패

super_ = super

class A(object):
    def x(self):
        print("No flipping")

class B(A):
    def x(self):
        super_().x()
>>> B().x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in x
RuntimeError: super(): __class__ cell not found

super()컴파일러의 도움없이 런타임에 수퍼 클래스를 확인할 수없는 이유는 무엇 입니까? 이 행동 또는 그에 대한 근본적인 이유가 경고하지 않는 프로그래머를 물리 칠 수있는 실제 상황이 있습니까?

... 및 부수적 인 질문 : 파이썬에서 함수, 메소드 등의 다른 예제가 다른 이름으로 리 바인드되어 깨질 수 있습니까?


6
나는 아르 민이에 대한 설명을 드리겠습니다 하나 . 이것은 또한 좋은 게시물입니다
Games Brainiac

답변:


217

super()DRY (Do n't Repeat Yourself) 원칙을 위반하지 않도록 새로운 마법 동작이 추가되었습니다 ( PEP 3135 참조) . 클래스를 전역 클래스로 참조하여 클래스 이름을 명시 적으로 지정해야하는 경우 super()자체적으로 발견 한 리 바인드 문제와 동일한 경향이 있습니다.

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

Spam = Foo
Foo = something_else()

Spam().baz()  # liable to blow up

데코레이터가 클래스 이름을 리 바인드하는 새 객체를 반환하는 클래스 데코레이터 사용에도 동일하게 적용됩니다.

@class_decorator_returning_new_class
class Foo(Bar):
    def baz(self):
        # Now `Foo` is a *different class*
        return super(Foo, self).baz() + 42

매직 super() __class__셀은 원래 클래스 객체에 대한 액세스 권한을 부여하여 이러한 문제를 회피합니다.

PEP는 처음 super에 키워드가 될 것으로 생각 했던 Guido에 의해 시작되었으며 현재 클래스를 조회하기 위해 셀을 사용한다는 아이디어 도 그의 것 입니다. 확실히, 키워드로 만드는 아이디어 는 PEP 초안의 일부였습니다 .

그러나 실제로 Guido 자신 은 키워드 아이디어에서 '너무 마술 적'을 벗어나 현재 구현을 제안했습니다. 그는 다른 이름을 사용하는 super()것이 문제가 될 것으로 예상했다 .

내 패치는 중간 솔루션 __class__ 을 사용합니다 'super'. 라는 변수를 사용할 때마다 필요하다고 가정합니다 . 따라서 (전역 적으로) 이름 super을 바꾸고 supper사용 supper하지만 이름 을 사용 super하지 않으면 인수없이 작동하지 않습니다 (그러나 __class__실제 클래스 객체 또는 객체 를 전달하면 여전히 작동 합니다). 관련이없는 변수가 super이면 작동하지만 메소드는 셀 변수에 사용되는 약간 느린 호출 경로를 사용합니다.

결국, super키워드 를 사용하는 것이 옳지 않다고, 마법 __class__세포 를 제공하는 것이 수용 가능한 타협 이라고 선포 한 것은 귀도 자신 이었습니다.

나는 구현의 마술, 암시 적 행동이 다소 놀랍지 만 super()언어에서 가장 잘못 적용되는 기능 중 하나 라는 데 동의합니다 . 인터넷에서 발견 된 모든 오용 super(type(self), self)또는 super(self.__class__, self)호출을 살펴보십시오 . 해당 코드 중 하나가 파생 클래스에서 호출 된 경우 무한 재귀 예외가 발생 합니다. 최소한의 단순화 된 super()호출은 인수없이이 문제를 피 합니다 .

이름이 바뀐 경우 super_; 단지 참조 __class__당신의 방법 뿐만 아니라 그것은 다시 작동합니다. 메소드에서 super 또는 __class__ 이름 을 참조하면 셀이 작성됩니다 .

>>> super_ = super
>>> class A(object):
...     def x(self):
...         print("No flipping")
... 
>>> class B(A):
...     def x(self):
...         __class__  # just referencing it is enough
...         super_().x()
... 
>>> B().x()
No flipping

1
좋은 글씨. 그러나 여전히 진흙처럼 분명합니다. super ()는 ? def super(of_class=magic __class__)와 같은 자동 인스턴스화 함수와 동일하다고 말하고 있습니다 self.super(); def super(self): return self.__class__.
Charles Merriam

17
@CharlesMerriam :이 글은 인수가없는 방법에 관한 것이 아닙니다 super(). 그것은 주로 존재 하는 이유를 다룹니다 . super(), 클래스 메소드에 상당하는 super(ReferenceToClassMethodIsBeingDefinedIn, self)경우, ReferenceToClassMethodIsBeingDefinedIn컴파일 시간에 결정이라는 고정의 방법에 부착되고 __class__, 및 super()실행시 호출 프레임에서 모두를 검색한다. 그러나 실제로이 모든 것을 알 필요는 없습니다.
Martijn Pieters

1
@CharlesMerriam : 그러나 자동 인스턴스화 기능에super() 가깝지 않습니다.
Martijn Pieters

1
@ chris.leonard : 핵심 문장은 super ()를 사용 __class__하거나 메소드에서 사용하면 셀이 생성됩니다 . super함수 에서 이름 을 사용했습니다 . 컴파일러는이를보고 __class__클로저를 추가합니다 .
Martijn Pieters

4
@Alexey : 충분 하지 않습니다. 메소드가 정의 된 유형과 동일하지 않은 현재 유형을 type(self)제공합니다 . 클래스 그래서 방법과 요구 가 같은 서브 클래스화할 수 있기 때문에, 포인트가있는, 이다 및 당신에게 무한 루프를 줄 것이다. 내 대답에서 링크 된 게시물을 참조하십시오. 파생 클래스에서 super ()를 호출 할 때 self .__ class__를 전달할 수 있습니까? Foobazsuper(Foo, self).baz()class Ham(Foo):type(self)Hamsuper(type(self), self).baz()
Martijn Pieters
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.