파이썬의 '비공개'메소드가 실제로 비공개가 아닌 이유는 무엇입니까?


658

파이썬은 다음과 같이 이름에 이중 밑줄을 추가하여 클래스 내에서 '비공개'메소드와 변수를 작성할 수있는 기능을 제공합니다 __myPrivateMethod(). 그렇다면 어떻게 이것을 설명 할 수 있습니까?

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
... 
>>> obj = MyClass()
>>> obj.myPublicMethod()
public method
>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: MyClass instance has no attribute '__myPrivateMethod'
>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']
>>> obj._MyClass__myPrivateMethod()
this is private!!

거래는 무엇입니까?!

나는 그것을 잘 얻지 못한 사람들을 위해 이것을 조금 설명 할 것입니다.

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
... 
>>> obj = MyClass()

내가 한 것은 공개 메소드와 개인 메소드로 클래스를 작성하고 인스턴스화하는 것입니다.

다음으로 공개 메소드를 호출합니다.

>>> obj.myPublicMethod()
public method

다음으로 개인 메서드를 시도하고 호출합니다.

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

여기 모든 것이 좋아 보인다; 우리는 그것을 부를 수 없습니다. 실제로 '비공개'입니다. 사실 그렇지 않습니다. 객체에서 dir () 을 실행 하면 파이썬이 모든 '비공개'메소드에 대해 마술처럼 만드는 새로운 마법 메소드가 나타납니다.

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

이 새로운 메소드의 이름은 항상 밑줄, 클래스 이름, 메소드 이름입니다.

>>> obj._MyClass__myPrivateMethod()
this is private!!

캡슐화에 너무 많은, 응?

어쨌든, 나는 항상 파이썬이 캡슐화를 지원하지 않는다고 들었습니다. 무엇을 제공합니까?


18
리플렉션을 사용하는 경우 Java 또는 C #에서도 마찬가지입니다.
0x434D53

4
이것은 유닛 테스팅 목적으로 만들어 졌기 때문에, 당신은 "해킹"을 사용하여 외부의 클래스의 프라이빗 메소드를 유닛 테스팅 할 수 있습니다.
waas1919

16
개인 메소드를 테스트하는 것이 안티 패턴이 아닙니까? 비공개 메소드는 공개 메소드에서 사용되어 영원히 사용되지 않습니다. 그리고 개인 메소드를 테스트하는 올바른 방법은 (ThinkWorks에서 지금까지 배운 것을 바탕으로) 모든 경우를 다루는 공개 메소드에 대해서만 테스트를 작성하는 것입니다. 제대로 작동하면 외부에서 개인용 메소드를 테스트 할 필요가 없습니다.
비슈누 나랑

3
@VishnuNarang : 예, 자주 가르치는 내용입니다. 그러나 항상 그렇듯이 " 항상 이렇게, 절대 그렇게하지 마십시오 "라는 거의 "종교적인"접근은 "절대"좋은 것이 유일한 것입니다. 단위 테스트가 회귀 테스트 또는 공용 API 테스트에 "전용"으로 사용되는 경우 개인 테스트는 필요하지 않습니다. 그러나 단위 테스트 기반 개발을 수행하는 경우 개발 중에 전용 메소드를 테스트해야하는 좋은 이유가 있습니다 (예 : 공용 인터페이스를 통해 비정상적이고 극단적 인 특정 매개 변수를 조롱하기 어려운 경우). IMHO가 좋지 않은 일부 언어 / 단위 테스트 환경에서는이 작업을 수행 할 수 없습니다.
Marco Freudenberger

5
@MarcoFreudenberger 당신의 요점을 참조하십시오. 단위 테스트 중심 개발 경험이 있습니다. 매개 변수를 조롱하기가 어려운 경우가 종종 디자인을 변경하고 개선하여 해결됩니다. 아직 디자인이 완벽하고 단위 테스트가 개인 메서드 테스트를 피하기가 매우 어려운 시나리오를 보지 못했습니다. 그런 경우를 살펴 보겠습니다. 감사. 이해를 돕기 위해 머리 위로 시나리오 하나를 공유해 주시면 감사하겠습니다.
비슈누 나랑

답변:


592

이름 스크램블링은 서브 클래스가 실수로 수퍼 클래스의 전용 메소드 및 속성을 대체하지 않도록하기 위해 사용됩니다. 외부에서 의도적으로 액세스하지 못하도록 설계되지 않았습니다.

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

>>> class Foo(object):
...     def __init__(self):
...         self.__baz = 42
...     def foo(self):
...         print self.__baz
...     
>>> class Bar(Foo):
...     def __init__(self):
...         super(Bar, self).__init__()
...         self.__baz = 21
...     def bar(self):
...         print self.__baz
...
>>> x = Bar()
>>> x.foo()
42
>>> x.bar()
21
>>> print x.__dict__
{'_Bar__baz': 21, '_Foo__baz': 42}

물론 두 개의 다른 클래스가 같은 이름을 가진 경우 분류됩니다.


12
docs.python.org/2/tutorial/classes.html . 개인 변수 및 클래스 로컬 참조에 관한 섹션 : 9.6.
gjain

72
스크롤 / 검색하기에는 너무 게으른 사람들 : 섹션 9.6 직접 링크
cod3monk3y

3
변수를 개인용으로 간주하도록 지정하려면 단일 밑줄을 사용해야합니다. 다시 말하지만, 누군가가 실제로 액세스하는 것을 방해하지는 않습니다.
igon

14
Guido는이 질문에 답했습니다. "(거의) 발견 할 수있는 모든 것이 디버깅하는 것이 주된 이유입니다. 디버깅 할 때 추상화를 자주 뚫어야합니다."-너무 늦어서 주석으로 추가했습니다. 너무 많은 답변입니다.
Peter M.-

1
"고의적 인 액세스 방지"기준을 따르는 경우 대부분의 OOP 언어는 진정한 개인 구성원을 지원하지 않습니다. 예를 들어 C ++에서는 메모리에 대한 원시 액세스 권한이 있으며 C #에서는 신뢰할 수있는 코드에서 개인 리플렉션을 사용할 수 있습니다.
코드 InChaos

207

개인 기능의 예

import re
import inspect

class MyClass :

    def __init__(self) :
        pass

    def private_function ( self ) :
        try :
            function_call = inspect.stack()[1][4][0].strip()

            # See if the function_call has "self." in the begining
            matched = re.match( '^self\.', function_call )
            if not matched :
                print 'This is Private Function, Go Away'
                return
        except :
            print 'This is Private Function, Go Away'
            return

        # This is the real Function, only accessible inside class #
        print 'Hey, Welcome in to function'

    def public_function ( self ) :
        # i can call private function from inside the class
        self.private_function()

### End ###

12
self = MyClass() self.private_function(). : D 물론 수업에서는 작동하지 않지만, 사용자 정의 기능을 정의하기 def foo(self): self.private_function()
만하면

161
확실하지 않은 경우를 대비하여 : 실제 코드에서는 절대로 하지 마십시오;)
Sudo Bash

10
@ThorSummoner 아니면 그냥 function_call.startswith('self.').
nyuszika7h

13
inspect.stack()[1][4][0].strip()<-그 1, 4, 0 매직 넘버는 무엇입니까?
akhy

5
이것은 수행함으로써 매우 쉽게 물리 칠 수 있으며 메소드 내부에서 self = MyClass(); self.private_function()호출하면 실패합니다 x = self.private_function().

171

Java에서 Python으로 처음 왔을 때 나는 이것을 싫어 했습니다. 그것은 나를 무서워했다.

오늘은 내가 파이썬에서 가장 좋아하는 것 중 하나 일 수 있습니다 .

나는 사람들이 서로를 믿으며 코드 주위에 뚫을 수없는 벽을 만들어야한다고 느끼지 않는 플랫폼에있는 것을 좋아합니다. 강력하게 캡슐화 된 언어에서 API에 버그가 있고 무엇이 잘못되었는지 파악한 경우 필요한 메소드가 비공개이기 때문에 여전히 문제를 해결할 수 없습니다. 파이썬에서 태도는 "확실히"입니다. 당신이 상황을 이해한다고 생각한다면, 아마도 당신은 그것을 읽었을 것입니다. 우리가 말할 수있는 것은 "행운입니다!"입니다.

캡슐화는 "보안"이나 아이들을 잔디밭에 두지 않는 것과 관련이 없습니다. 코드 기반을 이해하기 쉽도록 사용해야하는 또 다른 패턴 일뿐입니다.


36
@CamJackson Javascript가 그 예입니다 ?? 프로토 타입 기반 상속을 가진 유일한 널리 사용되는 언어와 함수형 프로그래밍을 선호하는 언어? JS는 전통적인 OOP에서 여러 직교 단계를 거치기 때문에 대부분의 다른 언어보다 배우기가 훨씬 어렵다고 생각합니다. 이것이 바보가 JS를 작성하는 것을 방해하지는 않는다. 그들은 단지 그것을 모른다;)
K.Steff

23
실제로 API는 캡슐화가 중요한 이유와 개인 메소드가 선호되는시기에 대한 좋은 예입니다. 비공개로 된 방법은 이후의 새 버전에서 사라지거나 서명 변경 또는 모든 변경 동작 중 최악의 상황이 발생할 수 있습니다. 똑똑한 성인 팀원이 업데이트 할 때부터 1 년 전부터 개인이 의도 한 방식으로 액세스했음을 기억합니까? 그녀는 더 이상 거기에서 일하고 있습니까?
einnocent

2
나는 그 주장에 동의하지 않는다. 프로덕션 코드에서는 필자가 공개 멤버를 "작동"하도록 변경하는 버그가있는 API를 사용하지 않을 것입니다. API가 작동해야합니다. 그렇지 않은 경우 버그 보고서를 제출하거나 동일한 API를 직접 작성합니다. 나는 철학이 마음에 들지 않고 파이썬을 좋아하지는 않지만, 그 구문으로 인해 작은 스크립트를 작성하는 것이 재미 있지만…
Yngve Sneen Lindal

4
Java에는 Method.setAccessible 및 Field.setAccessible이 있습니다. 또한 무섭습니까?
Tony

15
Java와 C ++의 적용은 Python이하는 동안 Java가 사용자를 불신하기 때문이 아닙니다. 컴파일러 및 / 또는 VM 이이 정보를 알고있는 경우 비즈니스에 관한 방법을 다룰 때 다양한 가정을 할 수 있기 때문에, 예를 들어 C ++은 가상 호출 대신 정기적으로 오래된 C 호출을 사용하여 전체 간접 계층을 건너 뛸 수 있습니다. 고성능 또는 고정밀 작업을 수행 할 때 중요합니다. 파이썬은 본질적으로 역 동성을 손상시키지 않으면 서 정보를 잘 활용할 수 없습니다. 두 언어 모두 서로 다른 것을 목표로하기 때문에 "틀린"것도 아닙니다
Shayne

144

에서 http://www.faqs.org/docs/diveintopython/fileinfo_private.html

엄밀히 말하면 개인 메소드는 클래스 외부에서 액세스 할 수 있으며 쉽게 액세스 할 수는 없습니다. 파이썬에는 아무것도 사적인 것이 없습니다. 내부적으로, 개인 메소드 및 속성의 이름은 지정된 이름으로 액세스 할 수없는 것처럼 보이게하기 위해 엉망이되어 있습니다. _MP3FileInfo__parse 이름으로 MP3FileInfo 클래스의 __parse 메소드에 액세스 할 수 있습니다. 이것이 흥미 롭다는 것을 인정하고 실제 코드에서는 절대로 그렇게하지 않겠다고 약속하십시오. 개인 메소드는 사적인 이유로 비공개이지만, 파이썬의 다른 많은 것들과 마찬가지로, 개인의 사유는 결국 강제가 아니라 관습의 문제입니다.


202
귀도 반 로섬 (Guido van Rossum)은 "우리는 모두 성인입니다."

35
-1 : 이것은 잘못입니다. 이중 밑줄은 절대 개인용으로 사용해서는 안됩니다. 아래 Alya의 대답은 이름 맹 글링 구문의 실제 의도를 알려줍니다. 실제 컨벤션은 단일 밑줄입니다.
nosklo

2
밑줄 하나만 사용하면 결과가 나타납니다. @nosklo
Billal Begueradj

93

일반적으로 사용되는 문구는 "우리는 모두 동의하는 성인입니다"입니다. 단일 밑줄 (노출하지 않음) 또는 이중 밑줄 (숨기기)을 앞에 추가하면 클래스 사용자에게 멤버가 어떤 식 으로든 '비공개'가 되겠다고 알려줍니다. 그러나 다른 모든 사람들이 책임감있게 행동하고 존중하지 않는 강력한 이유가없는 한 (예 : 디버거, 코드 완성)이를 신뢰해야합니다.

만약 당신이 정말로 사적인 것을 가지고 있어야한다면, 확장으로 구현할 수 있습니다 (예 : CPython의 경우 C). 그러나 대부분의 경우 파이썬 작업 방식을 배우기 만하면됩니다.


그래서 보호 된 변수에 액세스하는 데 사용해야하는 래퍼 프로토콜이 있습니까?
직관

3
"비공개"보다 더 "보호 된"변수가 없습니다. 밑줄로 시작하는 속성에 액세스하려면 할 수 있습니다 (그러나 저자는이를 권장하지 않습니다). 이중 밑줄로 시작하는 속성에 액세스해야하는 경우 이름을 직접 조작 할 수는 있지만 거의 그렇게하고 싶지는 않습니다.
Tony Meyer

33

어떤 언어 (C ++의 포인터 산술, .NET / Java의 리플렉션)에서 멤버의 사생활을 피할 수없는 것은 아닙니다.

요점은 실수로 개인 메서드를 호출하려고하면 오류가 발생한다는 것입니다. 그러나 발로 자신을 쏘고 싶다면 계속하십시오.

편집 : 당신은 OO 캡슐화로 물건을 보호하려고하지 않습니까?


2
전혀. 나는 단순히 개발자에게 쉽고, 개인적으로는 '비공개'속성에 액세스하는 마법 같은 방법을 제공하는 것이 이상하다고 지적하고 있습니다.
willurd

2
네, 요점을 설명하려고 노력했습니다. 비공개로 설정하면 컴파일러가 불만을 표시하여 "직접 액세스해서는 안됩니다"라고 표시됩니다. 그러나 실제로 할 수있는 일을 정말로 원합니다. 그러나 예, 대부분의 다른 언어보다 Python에서 더 쉽습니다.
막시밀리안

7
Java에서는 실제로 캡슐화를 통해 물건을 보호 할 수 있지만 SecurityManager에서 똑똑하고 신뢰할 수없는 코드를 실행해야하며 매우 조심해야합니다. 오라클조차도 때때로 잘못합니다.
안티몬

12

class.__stuff명명 규칙은 프로그래머가 자신이 액세스하는 것은 아닙니다 알 수 있습니다 __stuff외부에서. 이름 맹 글링은 누군가가 우연히 그것을 할 것 같지 않습니다.

사실, 당신은 여전히이 문제를 해결할 수 있지만 다른 언어 (BTW도 가능하게 함)보다 훨씬 쉽지만 캡슐화에 관심이 있다면 Python 프로그래머는이 작업을 수행하지 않습니다.


12

모듈 속성 이름이 단일 밑줄 (예 : _foo)로 시작하는 경우에도 유사한 동작이 존재합니다.

다음과 같이 이름이 지정된 모듈 속성은 from*메소드를 사용할 때 가져 오기 모듈로 복사되지 않습니다 .

from bar import *

그러나 이것은 언어 제한이 아닌 규칙입니다. 이들은 개인 속성이 아닙니다. 수입업자가 참조하고 조작 할 수 있습니다. 일부는 이것 때문에 파이썬이 진정한 캡슐화를 구현할 수 없다고 주장합니다.


12

언어 디자인 선택 중 하나 일뿐입니다. 어떤 수준에서 그들은 정당화됩니다. 그것들을 사용하면 메소드를 호출하고 호출하기 위해 당신의 길을 벗어나야하며, 정말로 그렇게 필요하다면 꽤 좋은 이유가 있어야합니다!

디버깅 후크 및 테스트는 당연히 책임감있게 사용되는 가능한 응용 프로그램으로 생각됩니다.


4

파이썬 3.4에서 이것은 동작입니다 :

>>> class Foo:
        def __init__(self):
                pass
        def __privateMethod(self):
                return 3
        def invoke(self):
                return self.__privateMethod()


>>> help(Foo)
Help on class Foo in module __main__:

class Foo(builtins.object)
 |  Methods defined here:
 |
 |  __init__(self)
 |
 |  invoke(self)
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)

 >>> f = Foo()
 >>> f.invoke()
 3
 >>> f.__privateMethod()
 Traceback (most recent call last):
   File "<pyshell#47>", line 1, in <module>
     f.__privateMethod()
 AttributeError: 'Foo' object has no attribute '__privateMethod'

https://docs.python.org/3/tutorial/classes.html#tut-private

맹 글링 규칙은 대부분 사고를 피하기 위해 고안되었습니다. 여전히 비공개로 간주되는 변수에 액세스하거나 수정할 수 있습니다. 이것은 디버거와 같은 특수한 상황에서도 유용 할 수 있습니다.

질문이 오래되었지만 스 니펫이 도움이되기를 바랍니다.


2

개인용 메소드와 속성에 대한 가장 중요한 관심사는 개발자에게 클래스 외부에서 호출하지 않도록 지시하는 것입니다. 이것이 캡슐화입니다. 캡슐화로 인한 보안을 오해 할 수 있습니다. 언급 한 것과 같은 구문을 의도적으로 사용하면 캡슐화를 원하지 않습니다.

obj._MyClass__myPrivateMethod()

나는 C #에서 마이그레이션했으며 처음에는 나에게도 이상했지만 잠시 후에 파이썬 코드 디자이너가 OOP에 대해 생각하는 방식이 다르다는 아이디어를 얻었습니다.


1

파이썬의 '비공개'메소드가 실제로 비공개가 아닌 이유는 무엇입니까?

내가 이해하는 것처럼 그들은 사적인 것이수 없습니다 . 프라이버시는 어떻게 시행 될 수 있습니까?

명백한 대답은 "비공개 멤버는 오직 통해서만 액세스 할 수 있습니다 self"입니다. 그러나 그것은 작동 self하지 않습니다. 파이썬에서는 특별하지 않습니다. 함수의 첫 번째 매개 변수에 일반적으로 사용되는 이름에 지나지 않습니다.

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