파이썬에는 클래스에 "비공개"변수가 있습니까?


578

나는 Java 세계에서 왔으며 Bruce Eckels의 Python 3 Patterns, Recipes and Idioms를 읽고 있습니다.

클래스에 대해 읽는 동안 파이썬에서는 인스턴스 변수를 선언 할 필요가 없다고 말합니다. 당신은 생성자에서 그것들을 사용하고 붐이 있습니다.

예를 들어 :

class Simple:
    def __init__(self, s):
        print("inside the simple constructor")
        self.s = s

    def show(self):
        print(self.s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

그것이 사실이라면 클래스의 모든 객체는 클래스 외부의 Simple변수 값을 변경할 수 있습니다 s.

예를 들면 다음과 같습니다.

if __name__ == "__main__":
    x = Simple("constructor argument")
    x.s = "test15" # this changes the value
    x.show()
    x.showMsg("A message")

Java에서는 공개 / 개인 / 보호 변수에 대해 배웠습니다. 이러한 키워드는 클래스 외부의 어느 누구도 액세스 할 수없는 클래스의 변수를 원하기 때문에 의미가 있습니다.

왜 파이썬에서는 이것이 필요하지 않습니까?


17
클래스 변수가 아닌 인스턴스 변수를 의미 했습니까?
PaulMcG

13
docs.python.org/library/functions.html#property 속성을 확인해야합니다 . getter를 사용하면 변수가 보호됩니다.
rubik

짧고 또렷한 답변이 여기 있습니다 . 이것이 도움이되기를 바랍니다.
Premkumar chalmeti

답변:


962

문화적입니다. 파이썬에서는 다른 클래스의 인스턴스 나 클래스 변수에 쓰지 않습니다. Java에서 실제로 원하는 경우 동일한 작업을 수행하는 데 방해가되는 것은 없습니다. 결국 동일한 클래스 효과를 얻기 위해 클래스 자체의 소스를 편집 할 수 있습니다. 파이썬은 보안을 강조하고 프로그래머가 책임을 지도록 장려합니다. 실제로 이것은 매우 훌륭하게 작동합니다.

어떤 이유로 개인 변수를 에뮬레이트하려는 경우 항상 PEP 8__접두사를 사용할 수 있습니다 . 파이썬은 변수의 이름처럼 엉망으로 그들은 당신이 있지만 (이를 포함하는 클래스 외부의 코드에 쉽게 볼 수없는 걸 그렇게 할 수 있습니다 당신은 그냥 같이있는 거 결정 충분히 당신이 경우 주위에 얻을 수있는 당신이 그것을 작동하는 경우 자바의 보호를 돌아 다니기 ).__foo

같은 규칙으로, _접두사는 기술적으로 금지되지 않은 경우에도 멀리 떨어져 있음을 의미 합니다. 당신은 __fooor 처럼 보이는 다른 클래스의 변수를 가지고 놀지 않습니다 _bar.


14
말이 되네요 그러나 자바에서 클래스 외부의 개인 변수에 액세스 할 수있는 방법이 없다고 생각합니다 (실제로 클래스의 소스를 변경하는 것을 제외하고). 있습니까?
Omnipresent

168
나는 파이썬 방식을 선호하는 경향이 있지만, 자바 방식이 당신이 만드는 것처럼 무의미하다고 생각하지 않습니다. 비공개로 선언하면 코드를 읽는 사람에게 매우 유용한 정보를 알려줍니다.이 필드는이 클래스 내에서만 수정됩니다.
Ned

67
@Omnipresent, 리플렉션을 사용할 수 있습니다.
rapadura

76
파이썬은 "보안의 척도가 있고 프로그래머가 책임을 지도록 장려하기 때문에"공개 속성이나 개인 속성을 구현하지 않지만, 커뮤니티는 "_"를 사용하여 개인 변수와 메소드를 표시하도록 권장합니까? 아마도 파이썬은 정의 적으로 공개 및 비공개를 가져야합니까? 주요 목적은 클래스와 상호 작용하기 위해 사용해야하는 API를 알려주는 것입니다. 이들은 이러한 방법을 사용하고 사용하지 말라고 알려주는 문서 역할을합니다. 그것들은 "보안의 척도"가 아니며, API 문서이며, 심지어 IDE를 통해 사용자를 안내 할 수도 있습니다!
PedroD

19
이것은 좋은 답변이며 귀하의 추론은 확실히 유효하지만 한 측면에 동의하지 않습니다. 액세스 수정 자의 목적은 결코 보안 이 아닙니다 . 오히려 이들은 클래스의 어떤 부분이 내부적으로 간주되고 해당 클래스의 외부 사용자에게 노출되는지 명시 적으로 구분 (및 대부분의 경우 적용)하는 수단입니다. 컨벤션 (문화)은 분명히 액세스 수정 자에 대한 올바른 대안이며 두 방법 모두 장단점이 있지만 언어 수준 액세스 수정자가 일반적인 의미에서 "보안"되도록 의도 된 것으로 오해의 소지가 있습니다. 워드.
devios1

159

파이썬의 개인 변수는 다소 해킹입니다. 인터프리터는 의도적으로 변수 이름을 바꿉니다.

class A:
    def __init__(self):
        self.__var = 123
    def printVar(self):
        print self.__var

이제 __var클래스 정의 외부에서 액세스하려고 하면 실패합니다.

 >>>x = A()
 >>>x.__var # this will return error: "A has no attribute __var"

 >>>x.printVar() # this gives back 123

그러나 다음과 같이 쉽게 벗어날 수 있습니다.

 >>>x.__dict__ # this will show everything that is contained in object x
               # which in this case is something like {'_A__var' : 123}

 >>>x._A__var = 456 # you now know the masked name of private variables
 >>>x.printVar() # this gives back 456

당신은 아마 OOP의 방법을 다음과 같이 호출되는 것을 알고 x.printVar() => A.printVar(x), 경우 A.printVar()에 일부 필드에 액세스 할 수 있습니다 x,이 필드는 액세스 할 수 밖에 A.printVar() ... 결국, 함수는 재사용을 위해 만들어, 내부의 문에 주어진 특별한 능력이 없다.

컴파일러가 관련된 경우 게임이 다릅니다 ( 개인 정보 보호는 컴파일러 레벨 개념입니다 ). 액세스 제어 수정자를 사용하여 클래스 정의에 대해 알고 있으므로 컴파일 타임에 규칙을 따르지 않으면 오류가 발생할 수 있습니다.


3
요컨대, 이것은 캡슐화가 아닙니다
watashiSHUN

2
PHP는 구피 개인 변수와 비슷한 것이 있는지 궁금합니다. 개인 변수는 해석 된 언어에서는 실제로 의미가 없으므로 x 변수가 개인 변수인지 알 수없는 최적화는 무엇입니까?
NoBugs

1
개인 변수의 패턴을 어떻게 무작위화할 수 있습니까?
crisron

@crisron 같은 질문
IanS

5
@watashiSHUN "즉, 이것은 캡슐화되지 않습니다"=> 그렇습니다. 캡슐화는 공개 API 만 사용하므로 클라이언트 코드는 구현 변경으로부터 보호됩니다. 명명 규칙은 API가 무엇인지, 구현이 무엇인지를 알려주는 완벽하게 유효한 방법이며, 요점은 그것이 작동한다는 것입니다.
bruno desthuilliers

30

위의 많은 의견에서 올바르게 언급했듯이 Access Modifiers의 주요 목표를 잊지 마십시오. 당신은 개인 필드를 볼 때 당신은 그것을 엉망으로하지 않습니다. 그래서 그것은 주로 구문 설탕으로 파이썬에서 _와 __에 의해 쉽게 달성됩니다.


4
나는 이것이 중요한 점이라고 생각합니다. 코드를 디버깅 할 때 (버그를 소개하는 약점이 있습니다) 멤버 변수를 변경할 수있는 클래스를 알면 디버깅 프로세스가 단순화됩니다. 적어도 변수가 일부 범위에 의해 보호되는 경우. 비슷한 개념은 C ++의 const 함수입니다. 멤버 변수가 변경되지 않았다는 것을 알고 있으므로 해당 방법을 잘못된 변수 설정의 잠재적 원인으로 보지조차 않습니다. 클래스 확장 / 추가 기능의 후속 개발이 가능하지만 코드의 가시성을 제한하면 디버그하기가 더 쉽습니다.
MrMas

18

밑줄 규칙에 개인 변수의 변형이 있습니다.

In [5]: class Test(object):
   ...:     def __private_method(self):
   ...:         return "Boo"
   ...:     def public_method(self):
   ...:         return self.__private_method()
   ...:     

In [6]: x = Test()

In [7]: x.public_method()
Out[7]: 'Boo'

In [8]: x.__private_method()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-fa17ce05d8bc> in <module>()
----> 1 x.__private_method()

AttributeError: 'Test' object has no attribute '__private_method'

약간의 미묘한 차이가 있지만 프로그래밍 패턴 이데올로기 적 순도를 위해 충분합니다.

@private 데코레이터에는 개념을 더 밀접하게 구현하지만 YMMV를 구현하는 예가 있습니다. 아마도 메타를 사용하는 클래스 정의를 작성할 수도 있습니다.


14
나는 이것이 파티에 꽤 늦었다는 것을 알고 있지만이 링크는 문제를 인터넷 검색 할 때 Google에 표시됩니다. 이것은 전체 이야기를 말하지 않습니다. __x클래스 내부의 변수 A가 실제로 컴파일러에 의해 다시 작성되기 때문에 _A__x여전히 완전히 개인용이 아니며 여전히 액세스 할 수 있습니다.
Zorf

1
물론이라는 변수가 보이면 _A__x만지지 않을 것입니다. 전염 될 수 있습니다. 나는 지옥에서 도망 칠 것이다.
Mateen Ulhaq

진정한 개인이 아닌지 확인하십시오 . 그러나 컴파일러 최적화 인 C ++ 및 Java 등의 강제 강제 개인에 대한 원칙 추론은 실제로 파이썬에는 존재하지 않으므로 컨벤션 개인이 충분합니다. 파이썬 컨벤션은 일반적으로 당신이 감독하지 않고 행동 할 것이라고 믿습니다. (그리고 그것의 초보자 함정이지만 클래스 디자인과 소비에 대해 신중하게 생각하십시오)
Shayne

14

"자바에서는 공개 / 개인 / 보호 변수에 대해 배웠다"

"파이썬에서는 왜 이것이 필요하지 않습니까?"

같은 이유로 Java 에서는 필요 하지 않습니다 .

당신은 무료로 사용할 수있어 - 사용 여부 privateprotected.

파이썬과 자바 프로그래머로서, 나는 것으로 나타났습니다 privateprotected매우 중요한 설계 개념이다. 그러나 실제적인 문제로서, 수십 자바와 파이썬의 라인의 수천에, 나는 결코 실제로 사용되지 privateprotected.

왜 안돼?

내 질문은 "누구에게서 보호 되었습니까?"입니다.

우리 팀의 다른 프로그래머? 그들은 소스를 가지고 있습니다. 보호 할 수있는 것은 무엇을 의미합니까?

다른 팀의 다른 프로그래머? 그들은 같은 회사에서 일합니다. 그들은 전화로 소스를 얻을 수 있습니다.

고객? 일반적으로 고용 작업 프로그래밍입니다. 클라이언트는 일반적으로 코드를 소유합니다.

그렇다면 누구로부터 정확히 보호하고 있습니까?


118
-1 : Porculus에 동의합니다. 액세스를 금지하거나 숨기는 것이 아니라 암시 적 API 문서에 관한 것입니다. 컴파일러 / 인터프리터 / 코드 검사기뿐만 아니라 개발자는 어떤 멤버를 사용하도록 권장하고 어떤 멤버를 건드리지 않아야하는지 (또는 적어도주의를 기울여야 함) 쉽게 확인할 수 있습니다. 대부분의 경우 클래스 또는 모듈의 모든 멤버가 공개 된 경우 끔찍한 혼란이 될 것입니다. 개인 / 보호 / 공개 회원을 서비스로 구분하여 다음과 같이 말합니다. "이 회원은 중요하지만 내부적으로 사용되며 유용하지 않을 수 있습니다."
Oben Sonne

7
@ S.Lott : API 문서가 우선 순위가 높으며 종종 API의 의도 된 용도를 전달하는 유일한 방법이라는 데 동의합니다. 그러나 때때로 회원의 이름과 가시성 (개인 / 공공의 관점에서)은 스스로 충분히 말할 수 있습니다. 또한 암시 적 문서의 아이디어는 API 검사가없는 편집기에서는 잘 작동하지 않지만 코드 완성이있는 IDE에서는 실제로 도움이된다는 점을 알고 있습니다. API 문서를 이미 읽었다 고 가정하면 클래스 사용 방법을 기억하는 데 도움이됩니다. 개인과 공개 회원 사이에 구별이 없다면 상황이 그렇게 똑똑하지 않을 것입니다.
Oben Sonne

21
늦은 토론 만에 모든 Porculus 및 Oben 완벽하게 적절하게이 규칙 '밑줄로 접두사 "에 의해 처리됩니다 여기에 요청하고 (그 대회의 컴파일러 집행이 발생할 수있는 피해 없음)
ncoghlan

38
@ S.Lott 나는 파이썬 사람이 아니므로 그 관점에서 언급하지 않을 것입니다. 그러나 자바 개발자로서 이것은 참으로 끔찍한 조언입니다. -1
dbyrne

11
와. 당신은 요점을 완전히 놓치고, 매우 나쁜 조언을하고,이 점에 대해 당신과 동의하지 않는 사람을 모욕하지만,이 "답변"에 대해 여전히 배지와 1000 점 이상의 평판을 얻습니다.
Eric Duminil

12

앞에서 언급했듯이 변수 나 메소드 앞에 밑줄을 붙여서 변수 나 메소드가 개인용임을 표시 할 수 있습니다. 이것으로 충분하지 않다면 언제든지 property데코레이터를 사용할 수 있습니다 . 예를 들면 다음과 같습니다.

class Foo:

    def __init__(self, bar):
        self._bar = bar

    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar

이런 식으로 누군가 또는 참조하는 bar것은 실제로 bar변수 자체가 아닌 함수 의 반환 값을 참조 하므로 액세스 할 수는 있지만 변경할 수는 없습니다. 그러나 누군가가 정말로 원한다면, 단순히 _bar새로운 가치를 사용 하고 할당 할 수 있습니다. 반복해서 말한 것처럼 누군가가 숨기고 싶은 변수와 메소드에 액세스하지 못하게하는 확실한 방법은 없습니다. 그러나 property변수를 편집하지 않도록 보낼 수있는 가장 명확한 메시지는 사용 하는 것입니다. https://docs.python.org/3/library/functions.html#property에property 설명 된대로 더 복잡한 getter / setter / deleter 액세스 경로에도 사용할 수 있습니다.


장고도 이것을 고맙게 생각합니다.
babygame0ver

10

파이썬은 클래스 이름을 두 개의 밑줄로 시작하는 식별자 앞에 자동으로 추가하는 기능을 통해 개인 식별자를 제한적으로 지원합니다. 이것은 프로그래머에게 투명하지만 대부분의 경우 이러한 방식으로 명명 된 변수는 전용 변수로 사용할 수 있습니다.

자세한 내용은 여기 를 참조 하십시오 .

일반적으로 파이썬의 객체 방향 구현은 다른 언어에 비해 약간 원시적입니다. 그러나 나는 이것을 실제로 즐긴다. 매우 개념적으로 간단한 구현이며 동적 언어 스타일에 잘 맞습니다.


네. 파이썬의 메타 프로그래밍 기능은 원하는 경우 실제로 멋진 것을 구현할 수 있다는 것을 의미합니다. (@ private / @ protected / etc 데코레이터와 물건을 구현하는 라이브러리도 있습니다. 심지어 JS 스타일 프로토 타입 클래스를 구현 한 라이브러리도 보았습니다. 제정신의 이유는 없지만) 실제로는 그다지 필요하지 않습니다. 나는 거의 사실이 아니기 때문에 "python / js / 무엇이든 lisp"밈을 싫어합니다. 그러나 파이썬은 단순한 구문과 결합 된 '메타 프로그래밍 절단' '그 언어로
Shayne

8

내가 개인 변수를 사용하는 유일한 시간은 변수에 쓰거나 읽을 때 다른 일을해야 할 때뿐이므로 setter 및 / 또는 getter를 강제로 사용해야합니다.

이미 언급했듯이 이것은 다시 문화로갑니다. 다른 클래스 변수를 읽고 쓰는 것이 자유로 웠던 프로젝트를 진행하고 있습니다. 하나의 구현이 더 이상 사용되지 않으면 해당 기능을 사용하는 모든 코드 경로를 식별하는 데 시간이 더 오래 걸렸습니다. setter와 getter를 강제로 사용하면 더 이상 사용되지 않는 메소드가 호출되었고이를 호출하는 코드 경로를 식별하기 위해 디버그 명령문을 쉽게 작성할 수 있습니다.

확장 프로그램을 작성할 수있는 프로젝트를 진행중인 경우, 몇 번의 릴리스에서 사라져야하는 더 이상 사용되지 않는 방법에 대해 사용자에게 알리므로 업그레이드시 모듈 손상을 최소화하는 것이 중요합니다.

내 대답은 다음과 같습니다. 당신과 동료들이 간단한 코드 세트를 유지한다면 클래스 변수를 보호 할 필요는 없습니다. 확장 가능한 시스템을 작성하는 경우 코드를 사용하는 모든 확장 프로그램에서 코어를 변경해야 할 때 반드시 변경해야합니다.


8

스레드를 "부활시키는"미안하지만, 이것이 누군가를 도울 수 있기를 바랍니다.

Python3에서 Java와 같이 클래스 속성을 "캡슐화"하려는 경우 다음과 같이 동일한 작업을 수행 할 수 있습니다.

class Simple:
    def __init__(self, str):
        print("inside the simple constructor")
        self.__s = str

    def show(self):
        print(self.__s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

이것을 인스턴스화하려면 다음을 수행하십시오.

ss = Simple("lol")
ss.show()

참고 : print(ss.__s)오류가 발생합니다.

실제로 Python3은 전역 속성 이름을 난독 화합니다. 이것을 Java처럼 "개인"속성처럼 바꾸십시오. 속성 이름은 여전히 ​​전역 적이지만 다른 언어의 개인 속성처럼 액세스 할 수없는 방식입니다.

그러나 두려워하지 마십시오. 중요하지 않습니다. 그것은 또한 일을한다. ;)


2
이것은 Python 1.5.2 IIRC 이후로 존재했으며 여전히 맹 글링 된 이름을 통해 속성에 액세스하는 것을 막지 않습니다.
bruno desthuilliers

7

개인 및 보호 개념이 매우 중요합니다. 그러나 파이썬-개발에 사용할 수있는 제한된 리소스로 프로토 타이핑 및 신속한 개발을위한 도구이므로 일부 보호 수준은 파이썬에서 엄격하게 따르지 않습니다. 클래스 멤버에서 "__"을 사용할 수 있지만 제대로 작동하지만 충분하지 않습니다. 이러한 필드에 액세스 할 때마다 이러한 문자가 포함됩니다.

또한 파이썬 OOP 개념이 완벽한 OOP 개념에 훨씬 가깝거나 완벽하지는 않습니다. C #이나 Java도 더 가깝습니다.

파이썬은 매우 좋은 도구입니다. 그러나 단순화 된 OOP 언어입니다. 구문 적으로 그리고 개념적으로 단순화되었습니다. 파이썬 존재의 주요 목표는 개발자에게 매우 높은 추상화 수준으로 쉽게 읽을 수있는 코드를 매우 빠르게 작성할 수있는 가능성을 제공하는 것입니다.


후자의 Private 및 Protected는 정적으로 컴파일 된 언어에서 컴파일러가 private 메소드에 대한 호출을 작성할 수 있지만 공용 메소드에 대한 찾아보기 테이블을 사용해야한다는 점이 중요합니다. Thiis는 단순히 동적 언어의 문제가 아닙니다. 마지막으로 C ++와 같은 언어는 상속 및 메서드 확인에 영향을 미칩니다. 파이썬과 루비는 OO의 구현이 매우 비슷하므로 비교는 의미가 없습니다. 스몰 토크는 실제로 공개 / 개인 메시지에 대한 개념이 없습니다. 카테고리로 비공개를 추가 할 수는 있지만 순전히 조언입니다.
Shayne

내 주장을 더 나아 가기 위해. 코드화 위생 관점에서, 예, 캡슐화에는 중요하지만, 필수 는 아니므로 @private (etc) 데코레이터는 무엇보다 조언이 많지만 개인 / 공개는 정적이 아닌 언어로, 자바 나 c와 같은 컴파일 된 언어에서와 같이 깊게 구현되지 않음
Shayne

4

Python에는 C ++ 또는 Java와 같은 전용 변수가 없습니다. 원하는 경우 언제든지 멤버 변수에 액세스 할 수 있습니다. 그러나 파이썬에서는 개인 변수가 필요하지 않습니다. 파이썬에서는 클래스 멤버 변수를 노출하는 것이 나쁘지 않기 때문입니다. 멤버 변수를 캡슐화해야하는 경우 기존 클라이언트 코드를 손상시키지 않고 나중에 "@property"를 사용하여이를 수행 할 수 있습니다.

파이썬에서 단일 밑줄 "_"은 메소드 또는 변수가 클래스의 공용 API의 일부로 간주되지 않으며 API의이 부분이 다른 버전간에 변경 될 수 있음을 나타내는 데 사용됩니다. 이 메소드 / 변수를 사용할 수 있지만이 클래스의 최신 버전을 사용하면 코드가 손상 될 수 있습니다.

이중 밑줄 "__"은 "개인 변수"를 의미하지 않습니다. 이를 사용하여 "클래스 로컬"이고 서브 클래스로 쉽게 오버라이드 할 수없는 변수를 정의합니다. 변수 이름을 엉망으로 만듭니다.

예를 들면 다음과 같습니다.

class A(object):
    def __init__(self):
        self.__foobar = None # will be automatically mangled to self._A__foobar

class B(A):
    def __init__(self):
        self.__foobar = 1 # will be automatically mangled to self._B__foobar

self .__ foobar의 이름은 클래스 A의 self._A__foobar로 자동 맹 글링됩니다. 클래스 B에서는 self._B__foobar로 맹 글링됩니다. 따라서 모든 하위 클래스는 부모 변수를 재정의하지 않고 자체 변수 __foobar를 정의 할 수 있습니다. 그러나 이중 밑줄로 시작하는 변수에 액세스하는 것을 막을 수있는 것은 없습니다. 그러나 이름을 변경하면이 변수 / 방법을 부수적으로 호출 할 수 없습니다.

Pycon 2013에서 제공하는 Raymond Hettingers의 "Pythons 클래스 개발 툴킷"(Youtube에서 제공)을보고 @property 및 "__"-인스턴스 변수를 사용해야하는 이유와 방법에 대한 좋은 예를 제공하는 것이 좋습니다.


그 대화를 확인하겠습니다. @property표준 파이썬의 일부 입니까 , 아니면 IDE에만 해당됩니까?
bballdave025

파이썬 2.6 이후 표준의 일부입니다. 이전 버전을 사용해야한다면, property내장 함수 를 사용할 가능성이 여전히 있습니다. 파이썬 2.2 이후부터 사용 가능
Hatatister

0

실제로 다음 C#과 같은 간단한 방법으로 게터와 세터를 시뮬레이션 할 수 있습니다 .

class Screen(object):

    def getter_setter_y(self, y, get=True):
        if get is True:
            Screen.getter_setter_y.value = y
        else:
            return Screen.getter_setter_y.value

     def getter_setter_x(self, x, get=True):
         if get is True:
             Screen.getter_setter_x.value = x
         else:
             return Screen.getter_setter_x.value

그런 다음 다음과 같이 사용하십시오 C#.

scr = Screen()
scr.getter_setter_x(100)
value =  scr.getter_setter_x(0, get=False)
print (value)

get / set 역할을 수행 할 함수에서 정적 로컬 변수를 선언하는 것입니다. 클래스 또는 파일에 전역 변수를 사용하지 않고 get 및 set 메소드를 통해 변수를 공유하는 유일한 방법이기 때문입니다.

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