객체 이름 앞에 단일 및 이중 밑줄의 의미는 무엇입니까?


답변:


1154

단일 밑줄

클래스에서 밑줄이있는 이름은 단순히 다른 프로그래머에게 속성 또는 메소드가 개인용임을 나타 내기위한 것입니다. 그러나 이름 자체로는 특별한 것이 없습니다.

PEP-8 을 인용하려면 :

_single_leading_underscore : "내부 사용"표시가 약합니다. 예를 들어 from M import *이름이 밑줄로 시작하는 객체는 가져 오지 않습니다.

이중 밑줄 (이름 맹 글링)

에서 파이썬 문서 :

양식의 식별자 __spam(최소한 두 개의 밑줄, 최대 한 개의 밑줄)는 텍스트로 대체됩니다 _classname__spam. 여기서 classname현재 밑줄이있는 밑줄이 제거됩니다. 이 맹 글링은 식별자의 구문 적 위치에 관계없이 수행되므로 클래스 전용 인스턴스 및 클래스 변수, 메소드, 전역에 저장된 변수 및 인스턴스에 저장된 변수를 정의하는 데 사용할 수 있습니다. 다른 클래스의 인스턴스에서이 클래스에 대해 비공개입니다.

같은 페이지의 경고 :

이름 맹 글링은 파생 클래스에 의해 정의 된 인스턴스 변수에 대해 걱정하거나 클래스 외부의 코드에 의해 인스턴스 변수와 결합 할 필요없이 클래스에 "개인"인스턴스 변수 및 메소드를 쉽게 정의 할 수 있도록하기위한 것입니다. 맹 글링 규칙은 대부분 사고를 피하기 위해 고안되었습니다. 결정된 영혼이 여전히 사적인 것으로 간주되는 변수에 액세스하거나 수정할 수 있습니다.

>>> class MyClass():
...     def __init__(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}

17
클래스에없는 2 개의 밑줄로 선언 된 변수 이름이 있으면 어떻게됩니까? 그것은 정상적인 변수 일뿐입니까?
Dhruv Ramani

5
__변수 이름으로 단순히 이중 밑줄 의 의미는 무엇 입니까? 처럼a, __ = foo()
AJ

104
이 답변은 독자가 Dunderscore를 사용하여 인스턴스 속성을 "비공개"로 만드는 것으로 믿기 때문에 오해의 소지가 있습니다. 입니다 하지 같은 경우 여기에서 설명하는 명시 적으로 민간의 반대 될 수 있도록 설계하는 동안 그 dunderscore이 잘못하면, 개인 마크 멤버에 사용되는 상태 레이몬드 Hettinger에 의해.
Markus Meskanen

13
@MarkusMeskanen 나는 동의하지 않는다. 대답은 클래스 전용 변수와 메소드의 인스턴스를 만들기 위해 천둥 스코어를 사용한다는 것을 명시 적으로 언급하고있다. Dunderscore는 서브 클래스에 의해 이러한 메소드 및 변수를 쉽게 겹쳐 쓰도록 (공개) 설계되었지만, Dunderscore를 사용하면 해당 클래스 내에서 사용할 수 있도록 전용 인스턴스가 보존됩니다.
arewm

6
@MarkusMeskanen : 서브 클래스가 수퍼 클래스를 방해하지 않고 수퍼 클래스와 같은 이름을 사용할 수있는 자유가 있습니다.
Ethan Furman

311

지금까지는 훌륭한 답변을 받았지만 약간의 허기가 없습니다. 하나의 주요 밑줄이 정확히되지 않습니다 단지 컨벤션 : 당신이 사용하는 경우 from foobar import *, 및 모듈 foobar정의하지 않는 __all__목록을 모듈에서 가져온 이름이 없는 최고의 밑줄있는 사람을 포함한다. 이 경우는 꽤 모호한 코너이기 때문에 대부분 컨벤션 이라고 가정 해 봅시다 .-).

선행 밑줄 규칙은 널리 단지에 사용되는 개인 이름뿐만 아니라 C ++에서라고 부르는 대한 보호 예를 들어, 완전히 의도 된 방법의 이름은 서브 클래스 (심지어 사람에 의해 오버라이드 (override) 할 수 - 사람을 가지고 에 있기 때문에 오버라이드 (override) 할 수 기본 클래스 (들) raise NotImplementedError!-)는 종종 해당 클래스 (또는 서브 클래스)의 인스턴스를 사용하여 코드 에 해당 메소드가 직접 호출되지 않는다는 것을 나타내는 단일 밑줄 이름 입니다.

예를 들어, FIFO 큐가 아닌 다른 분야와 스레드 안전 큐 있도록 한 수입 대기열 Queue.Queue 서브 클래스와 같은 방법을 대체 _get하고 _put; "클라이언트 코드는"결코 그 ( "훅") 메소드를 호출 없지만, 같은 아니라 ( "조직") public 메소드 putget(이것은로 알려져 템플릿 메소드 디자인 패턴 - 예를 들어, 참조 여기에 비디오를 기반으로 흥미로운 프리젠 테이션 성적표의 개요를 추가하여 주제에 대한 나의 이야기에 대한 이야기).

편집 : 대화 설명의 비디오 링크가 끊어졌습니다. 처음 두 비디오는 여기여기 에서 찾을 수 있습니다 .


1
그렇다면 여부를 사용하기로 결정 _var_name또는 사용 var_name+에서 제외 __all__?
endolith

3
@endolith 선행 밑줄을 사용하여 코드 독자에게이 코드를 사용해서는 안된다는 신호를 보냅니다 (예 : 버전 2.0 또는 1.1에서 변경할 수 있기 때문에). 대화식 인터프리터를 포함 __all__하여 모듈을 from spam import *친숙 하게 만들 때마다 명시 적으로 사용하십시오 . 따라서 대부분의 경우 대답은 둘 다 입니다.
abarnert

@AlexMartelli이 수입 관련 규칙이 문서 또는 다른 곳에서 합법적으로 논의 되었습니까?
Vicrobot

1
나는 C ++ 비유를 좋아한다. 첫째, 사람들이 _ private을 호출하면 싫어합니다 . 분명히 파이썬에서 사적인 것이 없기 때문에 유추에 대해 이야기하고 있습니다. 의미로 다이빙 나는 우리가를 묶을 수라고 말하고 싶지만 때 _자바로 보호 하기 때문에 proctected 자바 수단 "파생 클래스 및 / 또는 같은 패키지 내". PEP8은 이미 수입품 _에 대해 이야기 할 때 관습이 아니라고 알려주므로 패키지로 모듈을 교체하십시오 *. 클래스 내에서 식별자에 대해 말할 때 __Java의 개인 과 확실히 동일합니다 .
Marius Mucenicu 2016 년

2
괜찮은 답변이지만, 자체 홍보도 많이합니다.
하이브리드 웹 개발자

298

__foo__: 이것은 단지 규칙이며, 파이썬 시스템이 사용자 이름과 충돌하지 않는 이름을 사용하는 방법입니다.

_foo: 이것은 단지 관습에 불과합니다. 프로그래머가 변수가 개인임을 나타냅니다 (파이썬에서 의미하는 것).

__foo: 이것은 실제 의미를 갖습니다. 인터프리터는이 이름을 _classname__foo다른 클래스에서 유사한 이름과 겹치지 않도록하기 위해이 이름을 바꿉니다 .

파이썬 세계에서 다른 형태의 밑줄은 의미가 없습니다.

이 규칙에서 클래스, 변수, 전역 등의 차이점은 없습니다.


6
방금 와서 __foo궁금했다. 다른 클래스와 유사한 메소드 이름과 어떻게 겹칠 수 있습니까? 나는 여전히 instance.__foo()(통역사가 이름을 바꾸지 않은 경우) 계속 액세스해야한다는 것을 의미 합니까?
Bibhas Debnath

81
이 사람from module import *밑줄이 붙은 개체를 가져 오지 않는다고 말합니다 . 그러므로 _foo단순한 컨벤션 그 이상입니다.
dotancohen

4
@Bibhas : 클래스가 class를 B서브 클래스 A하고 둘 다 구현 하면 상속 된 from foo()B.foo()재정의합니다 . 의 인스턴스는 via를 제외하고 만 액세스 할 수 있습니다 . .foo()ABB.foo()super(B).foo()
naught101

3
들어 __dunder__는 (참조 어떤 경우에는 단지 명명 규칙보다 아마 조금 더 그래서 이름, 암시 적 호출은 인스턴스 사전을 건너 특별한 방법 조회 데이터 모델의 섹션).
wim

206

._variable 반 개인적이며 컨벤션을위한 것입니다

.__variable실제 의미는 우연히 액세스막기 위해 이름 을 짓는 것입니다. [1]

.__variable__ 일반적으로 내장 메소드 또는 변수 용으로 예약되어 있습니다.

.__mangled필사적으로 원하는 경우 변수에 계속 액세스 할 수 있습니다 . 이중 밑줄은 이름을 바꾸거나 변수의 이름을 바꿉니다.instance._className__mangled

예:

class Test(object):
    def __init__(self):
        self.__a = 'a'
        self._b = 'b'

>>> t = Test()
>>> t._b
'b'

t._b는 규칙에 의해서만 숨겨져 있으므로 액세스 가능

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'

t .__ a는 namemangling으로 인해 더 이상 존재하지 않으므로 찾을 수 없습니다

>>> t._Test__a
'a'

에 액세스하여 instance._className__variable대신 이중 밑줄 이름, 당신은 숨겨진 값에 액세스 할 수 있습니다


"__a"가 클래스 변수라면 파이썬 문서의 지시 사항으로도 액세스 할 수 없습니다.
Vitaliy Terziev

상속과 관련하여 이중 밑줄의 예로 답변을 업데이트 할 수 있습니까?
변수

116

처음에 단일 밑줄 :

파이썬에는 실제 개인 메소드가 없습니다. 대신, 메소드 또는 속성 이름 시작시 밑줄 하나는 API의 일부가 아니므로이 메소드에 액세스하면 안된다는 의미입니다.

class BaseForm(StrAndUnicode):

    def _get_errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

    errors = property(_get_errors)

(이 코드 스 니펫은 django 소스 코드 django / forms / forms.py에서 가져온 것입니다). 이 코드에서는 errors공용 속성이지만이 속성에서 호출하는 _get_errors 메서드는 "private"이므로 액세스해서는 안됩니다.

처음에 두 개의 밑줄 :

이것은 많은 혼란을 야기합니다. 개인 메소드를 작성하는 데 사용해서는 안됩니다. 서브 클래스가 메소드를 대체하거나 실수로 액세스하는 것을 피하기 위해 사용해야합니다. 예를 보자.

class A(object):
    def __test(self):
        print "I'm a test method in class A"

    def test(self):
        self.__test()

a = A()
a.test()
# a.__test() # This fails with an AttributeError
a._A__test() # Works! We can access the mangled name directly!

산출:

$ python test.py
I'm test method in class A
I'm test method in class A

이제 서브 클래스 B를 작성하고 __test 메소드에 대한 사용자 정의를 수행하십시오.

class B(A):
    def __test(self):
        print "I'm test method in class B"

b = B()
b.test()

출력은 ....

$ python test.py
I'm test method in class A

앞에서 살펴본 것처럼 A.test ()는 예상대로 B .__ test () 메서드를 호출하지 않았습니다. 그러나 실제로 이것은 __에 대한 올바른 동작입니다. __test ()라는 두 메서드는 자동으로 이름이 바뀌어 _A__test () 및 _B__test ()로 바뀌므로 실수로 재정의되지 않습니다. __로 시작하는 메소드를 작성할 때 다른 사용자가 메소드를 대체 할 수 없도록하고 자신의 클래스 내부에서만 액세스하려는 것을 의미합니다.

시작과 끝에 두 개의 밑줄 :

와 같은 메소드를 볼 때 __this__호출하지 마십시오. 이것은 당신이 아닌 파이썬이 호출하는 방법입니다. 한 번 보자:

>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11

>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60

이러한 마법 메서드를 호출하는 연산자 또는 기본 함수가 항상 있습니다. 때로는 특정 상황에서 훅 파이썬 호출 일뿐입니다. 예를 들어 인스턴스를 빌드하기 위해을 호출 __init__()한 후 객체가 생성되면 호출됩니다 __new__().

예를 들어 보자 ...

class FalseCalculator(object):

    def __init__(self, number):
        self.number = number

    def __add__(self, number):
        return self.number - number

    def __sub__(self, number):
        return self.number + number

number = FalseCalculator(20)
print number + 10      # 10
print number - 20      # 40

자세한 내용은 PEP-8 안내서를 참조하십시오 . 더 많은 마술 방법은 이 PDF를 참조하십시오 .


1
이 답변을 자신을 편집 한 후, 내가 선호하는 stackoverflow.com/a/8689983/1048186
제외 JosiahYoder-비활성화 ..

"A.test ()가 B .__ test () 메서드를 호출하지 않았습니다."라는 말의 의미는 무엇입니까?-A.test ()를 어디에서 호출 했습니까?
변수

18

때로는 다음과 같이 밑줄이있는 튜플 인 것처럼 보입니다.

def foo(bar):
    return _('my_' + bar)

이 경우 진행중인 작업은 _ ()가 로캘을 기반으로 올바른 언어 등으로 텍스트를 입력하는 텍스트에서 작동하는 지역화 함수의 별칭입니다. 예를 들어, 스핑크스는이 작업을 수행하며 수입품 중

from sphinx.locale import l_, _

sphinx.locale에서 _ ()는 일부 지역화 함수의 별칭으로 할당됩니다.


11

많은 사람들이 Raymond의 연설을 언급하고 있기 때문에 , 그가 말한 것을 적어두면 조금 더 쉽게 만들 수 있습니다.

이중 밑줄의 의도는 개인 정보 보호에 관한 것이 아닙니다. 의도는 정확히 이와 같이 사용하는 것이 었습니다

class Circle(object):

    def __init__(self, radius):
        self.radius = radius

    def area(self):
        p = self.__perimeter()
        r = p / math.pi / 2.0
        return math.pi * r ** 2.0

    def perimeter(self):
        return 2.0 * math.pi * self.radius

    __perimeter = perimeter  # local reference


class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

그것은 실제로 프라이버시와 반대입니다. 그것은 자유에 관한 것입니다. 서브 클래스가 다른 메소드를 중단하지 않고 한 메소드를 자유롭게 대체 할 수 있습니다 .

당신의 로컬 참조 유지하지 않는 말 perimeter에를 Circle. 이제 파생 클래스 Tireperimeter을 터치하지 않고 의 구현을 재정의합니다 area. Tire(5).area()이론 상으로는 을 호출 할 때 여전히 Circle.perimeter계산에 사용해야 하지만 실제로 Tire.perimeter의도 한 동작이 아닌을 사용하고 있습니다. 이것이 Circle에서 로컬 참조가 필요한 이유입니다.

그러나 왜 __perimeter대신에 _perimeter? _perimeter여전히 파생 클래스에 재정의 기회를 제공 하기 때문에 :

class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

    _perimeter = perimeter

이중 밑줄에는 이름이 맹 글링되므로 부모 클래스의 로컬 참조가 파생 클래스에서 재정의 될 가능성이 거의 없습니다. 따라서 " 서브 클래스가 다른 메소드를 중단하지 않고 한 메소드를 대체 할 수 있습니다 ".

클래스가 상속되지 않거나 메소드 재정의로 인해 아무것도 깨지지 않으면 단순히 필요하지 않습니다 __double_leading_underscore.


1
감사합니다. 슬라이드가 제대로 표시되지 않아서 코드가 실패하는 이유를 알 수 없었습니다.
cgte

8

변수를 읽기 전용으로 만들고 싶다면 IMHO가 가장 좋은 방법은 getter 만 전달 된 property ()를 사용하는 것입니다. property ()를 사용하면 데이터를 완전히 제어 할 수 있습니다.

class PrivateVarC(object):

    def get_x(self):
        pass

    def set_x(self, val):
        pass

    rwvar = property(get_p, set_p)  

    ronly = property(get_p) 

OP는 약간 다른 질문을했지만 이해하기 쉬운 '개인 변수를 설정하는 방법'을 묻는 다른 질문을 발견했기 때문에 여기에 추가 정보를 추가하려고 생각했습니다.


7

에 Accroding https://dbader.org/blog/meaning-of-underscores-in-python

  • 단일 선행 밑줄 (_var) : 이름을 나타내는 명명 규칙은 내부 용입니다. 일반적으로 파이썬 인터프리터 (와일드 카드 가져 오기 제외)에 의해 시행되지 않으며 프로그래머에게만 힌트가됩니다.
  • 단일 후행 밑줄 (var_) : Python 키워드와의 이름 충돌을 피하기 위해 규칙에 의해 사용됩니다.
  • Double Leading Underscore (__ var) : 클래스 컨텍스트에서 사용될 때 이름 맹 글링을 트리거합니다. 파이썬 인터프리터에 의해 시행됩니다.
  • 이중 선행 및 후행 밑줄 (__var__) : Python 언어로 정의 된 특수 메소드를 나타냅니다. 자신의 속성에 대해서는이 이름 지정 체계를 사용하지 마십시오.
  • 단일 밑줄 (_) : 때때로 임시 또는 중요하지 않은 변수의 이름으로 사용됩니다 ( "무관심"). 또한 : 파이썬 REPL의 마지막 표현의 결과.

5

훌륭한 답변과 모든 것이 정확합니다. 나는 간단한 정의 / 의미와 함께 간단한 예를 제공했습니다.

의미:

some_variable --► 누구나 볼 수있는 공개입니다.

_some_variable --► 누구나 공개적으로 볼 수 있지만 비공개로 표시하는 규칙입니다 ... 경고 는 Python에 의해 수행되지 않습니다.

__some_varaible --► Python은 변수 이름을 _classname__some_varaible (AKA 이름 맹 글링)로 바꾸고 가시성을 줄이거 나 숨기고 개인 변수와 비슷합니다.

파이썬 문서에 따르면 정직하게 말하면

"파이썬에는 객체 내부를 제외하고는 액세스 할 수없는"개인 "인스턴스 변수가 없습니다"

예를 들면 :

class A():
    here="abc"
    _here="_abc"
    __here="__abc"


aObject=A()
print(aObject.here) 
print(aObject._here)
# now if we try to print __here then it will fail because it's not public variable 
#print(aObject.__here)

_ _some_varaible는 - .... 그리고 / 감소 가죽 그것의 가시성을 더욱 전용 변수처럼. 아니요, 이름 맹 글링이 요점이며 방법을 숨기지 않습니다.
AMC

4

단일 밑줄은 규칙입니다. 이름이 단일 밑줄로 시작하는지의 여부는 통역사의 관점과 차이가 없습니다.

더블 선행 및 후행 밑줄에 사용되는 내장과 같은 방법, __init__, __bool__, 등

후행 대응이없는 이중 선행 밑줄도 규칙이지만, 클래스 메소드는 인터프리터에 의해 엉망이 됩니다. 변수 또는 기본 함수 이름의 경우 차이가 없습니다.


3

귀하의 질문은 좋습니다. 단지 방법에 관한 것이 아닙니다. 모듈의 함수와 객체는 일반적으로 하나의 밑줄로 시작하며 두 개의 접두사가 붙을 수 있습니다.

그러나 __double_underscore 이름은 예를 들어 모듈에서 이름이 표시되지 않습니다. 모듈에서 모든 모듈을 가져 오거나 (모듈 가져 오기 *에서) 이름이 help (module)에 표시되지 않으면 하나 이상의 밑줄로 시작하는 이름은 가져 오지 않습니다.


1
또한 두 개 이상의 후행 밑줄이있는 하나 이상의 밑줄로 시작하는 이름은 다른 이름으로 다시 작동합니다.
Bentley4

3

다음은 이중 밑줄 속성이 상속 된 클래스에 영향을 줄 수있는 간단한 예입니다. 따라서 다음 설정으로

class parent(object):
    __default = "parent"
    def __init__(self, name=None):
        self.default = name or self.__default

    @property
    def default(self):
        return self.__default

    @default.setter
    def default(self, value):
        self.__default = value


class child(parent):
    __default = "child"

그런 다음 파이썬 REPL에서 자식 인스턴스를 만들면 아래가 표시됩니다

child_a = child()
child_a.default            # 'parent'
child_a._child__default    # 'child'
child_a._parent__default   # 'parent'

child_b = child("orphan")
## this will show 
child_b.default            # 'orphan'
child_a._child__default    # 'child'
child_a._parent__default   # 'orphan'

이것은 일부에게는 분명 할 수 있지만 훨씬 더 복잡한 환경에서 나를 경계하게했습니다.


3

객체 내부를 제외하고는 액세스 할 수없는“비공개”인스턴스 변수는 Python에 없습니다. 그러나 대부분의 Python 코드가 따르는 규칙이 있습니다. 밑줄 (예 : _spam)이 접두어로 붙은 이름은 API의 비공개 부분으로 간주되어야합니다 (함수, 메소드 또는 데이터 멤버인지 여부) . 구현 세부 사항으로 간주되며 예고없이 변경 될 수 있습니다.

참조 https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references


1
_는 예를 들어 c #의 internal과 훨씬 유사하고 private과 훨씬 유사합니다. 이중 밑줄은 개인과 훨씬 유사하며 밑줄은 개인과 비슷합니다.
Ini

2

_와 __의 사실을 얻는 것은 매우 쉽습니다. 다른 답변들은 그것들을 꽤 잘 표현합니다. 사용법을 결정하기가 훨씬 어렵습니다.

이것이 내가 보는 방법입니다.

_

함수가 API와 같이 공용으로 사용되지 않음을 나타 내기 위해 사용해야합니다. 이것과 가져 오기 제한으로 인해 internalC # 에서처럼 동작합니다 .

__

상속 계층 구조에서 이름 충돌을 피하고 지연을 피하기 위해 사용해야합니다. C #의 private과 매우 유사합니다.

==>

무언가가 공개용이 아니라는 것을 나타내려면 use처럼 작동해야 protected합니다 _. 무언가가 공용이 아니라고 표시하고 싶지만 사용하는 것처럼 행동해야 private합니다.__ .

이것은 또한 내가 매우 좋아하는 인용문입니다.

문제는 클래스 작성자가 "이 속성 / 메소드 이름은 비공개 여야하고이 클래스 정의 내에서만 액세스 할 수 있어야합니다"라고 합법적으로 생각하고 __private 규칙을 사용할 수 있다는 것입니다. 그러나 나중에 해당 클래스의 사용자는 해당 이름에 합법적으로 액세스해야하는 서브 클래스를 만들 수 있습니다. 따라서 수퍼 클래스를 수정해야하거나 (어려울 수도 있고 불가능할 수도 있음) 서브 클래스 코드는 수동으로 맹 글링 된 이름을 사용해야합니다 (최악하고 깨지기 쉬운).

그러나 문제는 메소드를 재정의 할 때 경고하는 IDE가 없으면 기본 클래스의 메소드를 실수로 재정의 한 경우 오류를 찾는 데 시간이 걸릴 수 있다고 생각합니다.

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