파이썬에서 명시적인 '자기'를 피하는 방법은 무엇입니까?


131

나는 파이 게임 튜토리얼 을 따라 파이썬을 배우고있다 .

거기에서 키워드 self 의 광범위한 사용을 발견 했으며 주로 Java 배경에서 왔으므로 self 입력하는 것을 잊어 버렸습니다 . 예를 들어, rect 는 이미 클래스의 멤버 변수 이기 때문에을self.rect.centerx 입력 합니다.rect.centerx

자바 병렬 나는이 상황에 멤버 변수에 대한 모든 참조를 접두사 데에 대해 생각할 수있는 .

모든 멤버 변수 앞에 self 접두사를 붙였습니까 ? 그렇지 않도록 선언 할 수있는 방법이 있습니까?

내가 제안하는 것이 pythonic 이 아니더라도 가능하다면 여전히 알고 싶습니다.

나는 이와 관련된 SO 질문을 살펴 보았지만, 내가 겪고있는 것에 대해 대답하지 못했습니다.


5
나는 Java 배경에서 왔으며 자연 스럽지만 인스턴스 변수를 언급하고 있음을 분명히하기 위해 모든 호출에 명시 적으로 "this"를 추가합니다.
Uri

4
m_일부 C ++ / Java 프로그래머가 관찰 한 모든 멤버 이름 의 접두어 규칙에 익숙 하십니까? 사용 self.하면 비슷한 방식으로 가독성 이 향상 됩니다. 또한 dirtsimple.org/2004/12/python-is-not-java.html 을 읽어 보십시오 .
Beni Cherniavsky-Paskin

2
일반적으로 m_비공식 비 정적 데이터 멤버에만 사용 되지만 (적어도 C ++에서는).

@Beni 위대한 링크 기사 및 실제로 mVariableNameJava로 코딩 할 때 멤버 변수에 대해을 사용하는 규칙을 따릅니다 . @Anurag의 의견은 파이썬을 배울 때 Java 개발자가해야 할 일에 대해 잘 요약했다고 생각합니다.
bguiz

11
따라서 모든 사람들이 어떻게 자아를 사용하는 것이 좋거나 필요한지 등 OP에게 알리고 있습니다. 그러나 아무도 어떻게 든 피할 수 있는지 말하지 않습니까? 더러운 속임수로 도요?
einpoklum

답변:


99

파이썬은 self를 명시해야합니다. 결과적으로 전체 클래스 정의가 보이지 않아도 멤버와 그렇지 않은 것에 대해 혼동되지 않습니다. 이로 인해 다음과 같은 유용한 속성이 나타납니다.

하나의 극단적 인 예 : 어떤 기본 클래스에 대한 지식없이 클래스를 작성할 수 있으며 항상 멤버에 액세스하는지 여부를 알고 있습니다.

class A(some_function()):
  def f(self):
    self.member = 42
    self.method()

그것은 완전한 코드입니다! (some_function은 기본으로 사용되는 유형을 반환합니다.)

다른 클래스의 메소드는 동적으로 구성됩니다.

class B(object):
  pass

print B()
# <__main__.B object at 0xb7e4082c>

def B_init(self):
  self.answer = 42
def B_str(self):
  return "<The answer is %s.>" % self.answer
# notice these functions require no knowledge of the actual class
# how hard are they to read and realize that "members" are used?

B.__init__ = B_init
B.__str__ = B_str

print B()
# <The answer is 42.>

이 두 가지 예는 모두 극단적이며 매일 볼 수는 없으며 이와 같은 코드를 자주 작성해야한다고 제안하지는 않지만 명시 적으로 요구되는 자기 측면을 명확하게 보여줍니다.


4
감사합니다. 이 답변은를 사용하면 얻을 수있는 이점에 대해서도 설명합니다 self.
bguiz

2
@Roger Pate : 파이썬을 제거하기 위해 내 질문 편집을 중지하십시오. 나는 그것이 거기에 속한다고 생각합니다. (그리고 답변 주셔서 감사합니다!)
bguiz

3
@ bguiz : 제목에 태그를 복제하지 않는 것이 SO 규칙입니다. 그러나 2 일 전에 편집해도 7 개월 전에 제목을 되 돌리는 것을 보지 못했습니다.

1
자아를 단일 문자로 줄일 수 있다면 좋을 것입니다.
dwjohnston

5
그것은 실제로 다소 바보 같은 이유입니다. 파이썬은 섀도 잉을 받아들이지 못할 수 있으며, 섀도 잉 필드를 '축복'으로 명시해야합니다 __shadow__ myFieldName. 실수로 섀도 잉을 방지 할 수 있습니까?
einpoklum

39

이전 답변은 모두 기본적으로 "사용할 수 없음"또는 "사용할 수 없음"의 변형입니다. 나는 후자의 감정에 동의하지만, 기술적으로 여전히 대답하지 않습니다.

게다가, 누군가가 실제 질문이하는 것에 따라 누군가 무언가를하고 싶어 할만한 합당한 이유가 있습니다. 내가 때때로 겪는 한 가지는 긴 이름을 사용하면 방정식을 인식 할 수없는 긴 수학 방정식입니다. 미리 준비된 예에서이를 수행 할 수있는 몇 가지 방법은 다음과 같습니다.

import numpy as np
class MyFunkyGaussian() :
    def __init__(self, A, x0, w, s, y0) :
        self.A = float(A)
        self.x0 = x0
        self.w = w
        self.y0 = y0
        self.s = s

    # The correct way, but subjectively less readable to some (like me) 
    def calc1(self, x) :
        return (self.A/(self.w*np.sqrt(np.pi))/(1+self.s*self.w**2/2)
                * np.exp( -(x-self.x0)**2/self.w**2)
                * (1+self.s*(x-self.x0)**2) + self.y0 )

    # The correct way if you really don't want to use 'self' in the calculations
    def calc2(self, x) :
        # Explicity copy variables
        A, x0, w, y0, s = self.A, self.x0, self.w, self.y0, self.s
        sqrt, exp, pi = np.sqrt, np.exp, np.pi
        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)
                * exp( -(x-x0)**2/w**2 )
                * (1+s*(x-x0)**2) + y0 )

    # Probably a bad idea...
    def calc3(self, x) :
        # Automatically copy every class vairable
        for k in self.__dict__ : exec(k+'= self.'+k)
        sqrt, exp, pi = np.sqrt, np.exp, np.pi
        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)
                * exp( -(x-x0)**2/w**2 )
                * (1+s*(x-x0)**2) + y0 )

g = MyFunkyGaussian(2.0, 1.5, 3.0, 5.0, 0.0)
print(g.calc1(0.5))
print(g.calc2(0.5))
print(g.calc3(0.5))

세 번째 예, 즉 사용 for k in self.__dict__ : exec(k+'= self.'+k)은 기본적으로 질문이 실제로 요구하는 것이지만 일반적으로 좋은 생각이라고 생각하지 않는다는 것을 분명히하겠습니다.

클래스 변수 또는 함수를 반복하는 자세한 정보 및 방법은 이 질문에 대한 답변 및 토론을 참조하십시오 . 변수의 이름을 동적으로 지정하는 다른 방법과 이것이 일반적으로 좋지 않은 이유에 대한 설명은 이 블로그 게시물을 참조하십시오 .

업데이트 : Python3의 함수에서 로컬을 동적으로 업데이트하거나 변경할 수있는 방법 이 없으므로 calc3 및 유사한 변형이 더 이상 가능하지 않습니다. 내가 생각할 수있는 유일한 python3 호환 솔루션은 다음을 사용하는 것입니다 globals.

def calc4(self, x) :
        # Automatically copy every class variable in globals
        globals().update(self.__dict__)
        sqrt, exp, pi = np.sqrt, np.exp, np.pi
        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)
                * exp( -(x-x0)**2/w**2 )
                * (1+s*(x-x0)**2) + y0 )

다시 말하지만, 일반적으로 끔찍한 관행입니다.


4
훌륭한! 이것은 가장 유일무이 한 정답입니다. +1 당신은 또한 그것을하는 실용적인 이유를 유일하게줍니다. + 1i
David Lotts

클래스를 만들고 그 안에 코드를 옮긴 후 : 이제 모든 메소드와 변수가 더 이상 인식되지 않습니다 ( 자기 없음 ..) 나는 파이썬의 또 다른 이유를 생각 나게 하고 나아지지 않습니다 . 아이디어로 감사드립니다. 전반적인 / headache / unreadability 문제를 해결하지는 않지만 적당한 해결 방법을 제공합니다.
javadba

locals대신에 업데이트 하지 exec않습니까?
나단

locals().update(self.__dict__)파이썬 2와 3에서 시도했지만 작동하지 않았습니다. python3에서는 'exec'트릭조차 더 이상 옵션이 아닙니다. 반면에 globals().update(self.__dict__)효과는 있지만 일반적으로 끔찍한 관행입니다.
argentum2f

26

실제로 self는 키워드가 아니며, 파이썬에서 인스턴스 메소드의 첫 번째 매개 변수에 일반적으로 부여 된 이름 일뿐입니다. 그리고 첫 번째 매개 변수는 메소드가 호출중인 클래스의 인스턴스를 아는 유일한 메커니즘이므로 건너 뛸 수 없습니다.


1
이 답변, 특히 두 번째 문장은 '명시 적 자아'가 파이썬의 한계 중 하나이며 피할 수 없다는 것을 알 수 있기 때문에 나에게 허용되는 답변보다 훨씬 유용합니다.
QuestionDriven

21

예를 들어 원하는 이름을 사용할 수 있습니다

class test(object):
    def function(this, variable):
        this.variable = variable

또는

class test(object):
    def function(s, variable):
        s.variable = variable

그러나 당신은 범위의 이름을 사용하여 붙어 있습니다.

나는 당신이 설득력있는 이유가 없다면 경험이 풍부한 pythonistas에게 외계인이 될 수 있기 때문에 자기 자신과 다른 것을 사용하지 않는 것이 좋습니다.


26
당신은 이것을 할 수 있지만, 하지 않습니다 ! 필요 이상으로 코드를 이상하게 만들 이유가 없습니다. 예, 무엇이든 호출 할 수 있지만 컨벤션은이를 호출하는 self것이며 컨벤션을 따라야합니다. 숙련 된 Python 프로그래머라면 코드를 쉽게 이해할 수 있습니다. (이는 이전 프로그램이 무엇을 알아 내려고 노력, 지금부터 6 개월을 포함!)
steveha

3
훨씬 더 외계인 :def function(_, variable): _.variable = variable
밥 스타 인

1
@ BobStein-VisiBone 훨씬 더 외계인 :def funcion(*args): args[0].variable = args[1]
Aemyl

4
@ steveha 그는 그것을 권장하지 않습니다.이 정보는 나 자신과 다른 키워드를 사용할 수 있고 자신의 클래스의 객체가 왜 전달되는지 궁금한 저 같은 사람들에게 매우 유용합니다.
스벤 반 덴 부가 아트

> "이상하다". 파이썬 이상합니다-특히 클래스 구조 이며이 자체 사용은 가독성을 지원하는 카나리아입니다. 나는 많은 수비수들이 이것 이후에 올 것이라는 것을 알고 있지만 그것이 진실을 바꾸지는 않습니다.
javadba

9

selfpython 철학에 따르면 명시 적이 암시 적보다 낫기 때문에 항상을 지정해야합니다 .

파이썬으로 프로그래밍하는 방식이 자바로 프로그래밍하는 방식과 매우 다르다는 self것을 알 수 있습니다. 따라서 객체 내부의 모든 것을 투영하지 않기 때문에 사용 이 감소하는 경향이 있습니다. 오히려 더 나은 테스트를 위해 모듈 수준 기능을 더 많이 사용합니다.

그건 그렇고. 나는 처음에 그것을 싫어, 지금은 반대 싫어. 들여 쓰기 방식의 흐름 제어에 대해서도 동일합니다.


2
"더 나은 테스트를 할 수있는 모듈 수준의 기능을 더 많이 사용한다"는 의문의 여지가 있으며, 매우 동의하지 않아야한다. "논리적으로 모듈 수준"인지 여부에 관계없이 모든 클래스를 메소드 (정적 또는 비 정적)로 만들지 않아도됩니다. 한 가지 방법 또는 다른 방법으로 테스트 (나를 위해).

내 경험에서 비롯됩니다. 매번 만트라로 따르지는 않지만 멤버 변수 액세스가 필요없는 것을 별도의 독립적 인 방법으로 넣는 경우 테스트하기가 더 쉽습니다. 예, 데이터와 논리를 분리합니다. 예, OOP에 반하는 것이지만 모듈 수준에서 함께 있습니다. 나는 하나 또는 다른 하나에 "최고의"마크를주지 않고 단지 맛의 문제 일 뿐이다. 때로는 클래스 자체와 아무런 관련이없는 클래스 메소드를 지정하는 경우가 있습니다 self. 수업 시간에 무엇을해야할까요?
Stefano Borini

나는 그것의 두 부분에 동의하지 않습니다 (다른 언어보다 "비 방법"을 더 자주 사용하지 않는 것 같지만) "더 나은 테스트를 할 수있는"것은 한 가지 방법이 다른 방법보다 우수하다는 것을 의미합니다 ( 내 경험에서 그에 대한 지원을 찾지 못하는 동안 읽지 않겠습니까?) 나는 항상 하나 또는 다른 것을 사용해야한다고 말하는 것이 아니라 메소드와 비 메소드를 똑같이 테스트 할 수 있다고 말하는 것입니다.

5
물론 가능하지만 접근 방식은 다릅니다. 객체에는 상태가 있지만 모듈 수준 방법에는 없습니다. 클래스 레벨 메소드를 테스트하는 동안 테스트가 실패하면 두 가지가 잘못되었을 수 있습니다. 1) 호출 당시의 오브젝트 상태 2) 메소드 자체. 상태 비 저장 모듈 수준 방법이있는 경우 사례 2 만 발생할 수 있습니다. 테스트 대상으로 복잡한 개체 논리가 적용되므로 테스트와 관련하여 블랙 박스 인 설정에서 테스트 설정으로 설정을 이동했습니다. 복잡성을 줄이고 설정을보다 엄격하게 제어하고 있습니다.
Stefano Borini

1
"상태 비 저장 모듈 수준 방법이있는 경우"상태 저장 모듈 수준 방법은 어떻습니까? 스테이트리스 함수는 스테이트 풀 함수보다 테스트하기 쉽다는 점에 동의합니다. 그러나 이에 동의 할 것입니다. 자체 매개 변수를 정확히 다음과 같이보십시오. 함수에 대한 다른 매개 변수.

4

"self"는 클래스의 현재 객체 인스턴스의 일반적인 자리 표시 자입니다. 마치 "자체"를 참조하는 것처럼 클래스 내부의 객체 속성 또는 필드 또는 메서드를 참조하려고 할 때 사용됩니다. 그러나 파이썬 프로그래밍 영역의 누군가가 "self"를 사용하기 시작하자마자 다른 영역은 "this"를 사용하지만 대체 할 수없는 키워드로 만듭니다. 코드 가독성을 높이기 위해 "its"를 사용했습니다. 파이썬에서 좋은 점 중 하나입니다. "self"이외의 객체 인스턴스에 대한 자리 표시자를 자유롭게 선택할 수 있습니다. 자기 예 :

class UserAccount():    
    def __init__(self, user_type, username, password):
        self.user_type = user_type
        self.username = username            
        self.password = encrypt(password)        

    def get_password(self):
        return decrypt(self.password)

    def set_password(self, password):
        self.password = encrypt(password)

이제 'self'를 'its'로 바꿉니다.

class UserAccount():    
    def __init__(its, user_type, username, password):
        its.user_type = user_type
        its.username = username            
        its.password = encrypt(password)        

    def get_password(its):
        return decrypt(its.password)

    def set_password(its, password):
        its.password = encrypt(password)

어느 것이 지금 더 읽을 수 있습니까?


왜 그냥 s(또는 다른 단일 문자) 대신its
javadba

'그'는 의미가 있고 's'는 의미가 없습니다.
LEMUEL ADANE

s클래스 인스턴스의 별명과 같은 의미입니다. 나는 its문맥에서 그 의미가 똑같은 것을
찾아야 만했다

둘 다 읽을 수 없습니다. "자기 자신"을 외부 매개 변수로 사용하는 것은 여전히 ​​비논리적이며 아무런 의미가 없습니다.
Cesar

3

self는 객체의 멤버에 액세스하기위한 python 구문의 일부이므로이를 사용하는 것이 두렵습니다.


2
self는 실제로 하나를 사용하지 않고 액세스 수정 자에게 알리는 방법입니다. +1
Perpetualcoder

1

실제로 Armin Ronacher 프리젠 테이션 "5 년 동안의 나쁜 아이디어"(google it)의 "암시 적 자체"레시피를 사용할 수 있습니다.

Armin Ronacher의 거의 모든 것과 마찬가지로 매우 영리한 조리법이지만이 아이디어가 매우 매력적이라고 ​​생각하지 않습니다. 내가 명시 적으로 선호하는 거라고 생각 C # / 자바.

최신 정보. "나쁜 아이디어 레시피"링크 : https://speakerdeck.com/mitsuhiko/5-years-of-bad-ideas?slide=58


인가 이것은 당신이 언급 된 것을 언급하는 링크? 그렇다면 pls가 귀하의 답변에 포함되는 경우
reubenjohn

아니, Armin "나쁜 생각"은 내 취향에 더 재미있어 보인다. 링크를 포함 시켰습니다.
Alex Yu

레시피 링크를 클릭하기 전에 def method(<del> self </ del> )매개 변수 목록에 암시 적으로 표시되지만 self.variable이 영리한 핵에는 여전히 필요합니다.
David Lotts

0

예, 자기는 지루합니다. 그러나 더 낫습니까?

class Test:

    def __init__(_):
        _.test = 'test'

    def run(_):
        print _.test

10
_파이썬 쉘에서 특별한 의미를 가지며, 마지막 반환 값을 보유합니다. 이와 같이 사용하는 것이 안전하지만 혼동 될 수 있습니다. 나는 그것을 피할 것이다.
Cairnarvon

아니, 더 좋지는 않지만 왜 단일 문자 대신 s또는 또는 m(C ++를 모방하기 위해)
javadba

0

From : Self Hell-보다 상태 저장 기능.

... 하이브리드 방식이 가장 효과적입니다. 실제로 계산을 수행하는 모든 클래스 메소드는 클로저로 이동해야하며 구문 정리를위한 확장은 클래스에 보관해야합니다. 클래스를 네임 스페이스처럼 처리하여 클로저를 클래스에 넣습니다. 클로저는 본질적으로 정적 함수이므로 클래스에서도 selfs *가 필요하지 않습니다.


소규모 유스 케이스에는 클로저가 좋지만, 클래스 유스 OO가 아닌 프로토 타입 기반 OO를 사용하므로 각 오브젝트마다 고유 한 기능 세트가 필요하므로이를 사용하면 프로그램의 메모리 오버 헤드가 상당히 증가합니다. 오히려 클래스의 공통 함수 세트를 유지). 또한, __str__일반적인 방법과는 다른 방식으로 호출되기 때문에 마술 등의 방법 (예 : 기타)을 사용할 수 없게됩니다 .
모래 언덕

0

나는“전역”이있는 것처럼“member”라는 문장이 있으면 더 쉽고 더 읽기 쉽다고 생각하므로 통역사에게 클래스의 객체 멤버가 무엇인지 알 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.