[python] 왜 파이썬 메소드에 “self”인수가 명시 적으로 필요합니까?

파이썬에서 클래스에 메소드를 정의 할 때 다음과 같이 보입니다 :

class MyClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

그러나 C #과 같은 다른 언어에서는 메소드 프로토 타입에서 인수로 선언하지 않고 메소드가 “this”키워드를 사용하여 바인딩 된 오브젝트에 대한 참조가 있습니다.

이것은 파이썬에서 의도적 인 언어 디자인 결정입니까, 아니면 “자기”를 인수로 전달해야하는 구현 세부 사항이 있습니까?



답변

저는 Peters의 Zen of Python을 인용하고 싶습니다. “명시적인 것이 묵시적인 것보다 낫다.”

Java 및 C ++에서 this.추론을 불가능하게하는 변수 이름이있는 경우를 제외하고 ‘ ‘를 추론 할 수 있습니다. 따라서 때로는 필요하지만 때로는 필요하지 않습니다.

파이썬은 규칙에 기반하기보다는 이와 같은 것을 명시 적으로 선택합니다.

또한 암시되거나 가정 된 것이 없으므로 구현의 일부가 노출됩니다. self.__class__, self.__dict__및 기타 “내부”구조는 명백한 방법으로 사용할 수 있습니다.


답변

방법과 기능의 차이를 최소화하는 것입니다. 메타 클래스에서 메소드를 쉽게 생성하거나 런타임시 기존 클래스에 메소드를 추가 할 수 있습니다.

예 :

>>> class C(object):
...     def foo(self):
...         print "Hi!"
...
>>>
>>> def bar(self):
...     print "Bork bork bork!"
...
>>>
>>> c = C()
>>> C.bar = bar
>>> c.bar()
Bork bork bork!
>>> c.foo()
Hi!
>>>

또한 (내가 아는 한) 파이썬 런타임을 쉽게 구현할 수 있습니다.


답변

나는 사람이 읽어야하는 것이 좋습니다 귀도 반 로섬 (Guido van Rossum)의 블로그 -이 주제에 대한 명시 적 자기 유지하는 이유는 .

메소드 정의가 데코레이션 될 때 자동으로 ‘self’매개 변수를 제공할지 여부를 알 수 없습니다. 데코레이터는 함수를 정적 메소드 ( ‘self’가없는) 또는 클래스 메소드 ( 인스턴스 대신 클래스를 참조하는 재미있는 종류의 자체가 있거나 완전히 다른 무언가를 할 수 있습니다 (순수한 파이썬에서 ‘@classmethod’또는 ‘@staticmethod’를 구현하는 데코레이터를 작성하는 것은 쉽지 않습니다). 메소드가 암시적인 ‘self’인수로 정의되는지 여부를 데코레이터가 무엇을하는지 알지 못하면 방법이 없습니다.

특수한 ‘@classmethod’및 ‘@staticmethod’와 같은 핵을 거부합니다.


답변

파이썬은 “self”를 사용하도록 강요하지 않습니다. 원하는 이름을 지정할 수 있습니다. 메소드 정의 헤더의 첫 번째 인수는 객체에 대한 참조임을 기억하면됩니다.


답변

또한 이렇게하면 다음과 같은 작업을 수행 할 수 있습니다. (요컨대, 호출 Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5)하면 12가 반환되지만 가장 열중 한 방법으로 호출 됩니다.

class Outer(object):
    def __init__(self, outer_num):
        self.outer_num = outer_num

    def create_inner_class(outer_self, inner_arg):
        class Inner(object):
            inner_arg = inner_arg
            def weird_sum_with_closure_scope(inner_self, num)
                return num + outer_self.outer_num + inner_arg
        return Inner

물론 이것은 Java 및 C #과 같은 언어에서는 상상하기 어렵습니다. 자체 참조를 명시 적으로 작성하면 해당 자체 참조로 오브젝트를 자유롭게 참조 할 수 있습니다. 또한 런타임에 클래스를 사용하는 이러한 방법은 더 정적 인 언어에서는 수행하기가 더 어렵습니다. 반드시 좋은지 나쁜지는 아닙니다. 그것은 명백한 자아가이 모든 광기의 존재를 허용한다는 것입니다.

또한, 이것을 상상해보십시오 : 우리는 메소드의 동작 (프로파일 링 또는 미친 흑 마법)을 사용자 정의하고 싶습니다. 이를 통해 우리는 생각을 Method할 수 있습니다.

여기 있습니다 :

from functools import partial

class MagicMethod(object):
    """Does black magic when called"""
    def __get__(self, obj, obj_type):
        # This binds the <other> class instance to the <innocent_self> parameter
        # of the method MagicMethod.invoke
        return partial(self.invoke, obj)


    def invoke(magic_self, innocent_self, *args, **kwargs):
        # do black magic here
        ...
        print magic_self, innocent_self, args, kwargs

class InnocentClass(object):
    magic_method = MagicMethod()

그리고 지금 : InnocentClass().magic_method()예상대로 행동합니다. 이 메서드는 innocent_self매개 변수 to InnocentClassmagic_selfMagicMethod 인스턴스에 바인딩됩니다 . 허드? 2 개의 키워드가 this1있고 this2Java 및 C #과 같은 언어로되어 있습니다. 이와 같은 마술은 프레임 워크가 훨씬 더 장황한 것들을 할 수있게합니다.

다시, 나는이 물건의 윤리에 대해 언급하고 싶지 않다. 나는 명백한 자기 참조 없이는하기 어려운 것들을 보여주고 싶었습니다.


답변

“파이썬 (Zen of Python)”외에 실제 이유는 함수가 파이썬에서 일류 시민이라는 것입니다.

본질적으로 그것들을 객체로 만듭니다. 이제 근본적인 문제는 함수가 객체 인 경우 객체 지향 패러다임에서 메시지 자체가 객체 일 때 객체에 메시지를 보내는 방법은 무엇입니까?

이 역설을 줄이기 위해 닭고기 달걀 문제처럼 보이는 유일한 방법은 실행 컨텍스트를 메소드에 전달하거나 감지하는 것입니다. 그러나 파이썬은 중첩 함수를 가질 수 있기 때문에 실행 컨텍스트가 내부 함수에 대해 변경되므로 그렇게 할 수 없습니다.

이것은 가능한 유일한 해결책은 명시 적으로 ‘self'(실행 컨텍스트)를 전달하는 것입니다.

그래서 Zen이 훨씬 나중에 구현 문제라고 생각합니다.


답변

PEP 227과 관련이 있다고 생각합니다.

클래스 범위의 이름은 액세스 할 수 없습니다. 가장 안쪽에있는 함수 범위에서 이름이 확인됩니다. 중첩 된 범위의 체인에서 클래스 정의가 발생하면 해결 프로세스는 클래스 정의를 건너 뜁니다. 이 규칙은 클래스 속성과 로컬 변수 액세스 간의 이상한 상호 작용을 방지합니다. 클래스 정의에서 이름 바인딩 조작이 발생하면 결과 클래스 오브젝트에 속성이 작성됩니다. 메소드 또는 메소드 내에 중첩 된 함수에서이 변수에 액세스하려면 자체 또는 클래스 이름을 통해 속성 참조를 사용해야합니다.