etc./StackOverFlow

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

청렴결백한 만능 재주꾼 2022. 2. 27. 12:39
반응형

질문자 :Community Wiki


누군가 Python에서 객체 이름 앞에 단일 및 이중 선행 밑줄이 있는 정확한 의미와 둘의 차이점을 설명해 주시겠습니까?

또한 해당 객체가 변수든, 함수든, 메소드 등이든 상관없이 그 의미는 동일하게 유지됩니까?



단일 밑줄

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

PEP-8 인용:

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

이중 밑줄(이름 맹글링)

Python 문서에서 :

__spam 형식의 식별자(최소 2개의 선행 밑줄, 최대 1개의 후행 밑줄)는 텍스트로 _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!'}

Andrew Keeton

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

_foo : 이것은 단지 관례일 뿐입니다. 프로그래머가 변수가 private임을 나타내는 방법입니다(파이썬에서 그것이 무엇을 의미하든지 간에).

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

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

이러한 규칙에는 클래스, 변수, 전역 등의 차이가 없습니다.


Ned Batchelder

지금까지 훌륭한 답변이지만 일부 정보가 누락되었습니다. 하나의 주요 밑줄 정확히 단지 컨벤션되지 않습니다 : 당신이 사용하는 경우 from foobar import * , 및 모듈 foobar 정의하지 않습니다 __all__ 목록을 모듈에서 가져온 이름은 최고의 밑줄 가진 사람들이 포함되어 있지 않습니다. 이 경우는 꽤 모호한 코너이기 때문에 대부분 이 관례라고 가정해 보겠습니다.-).

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

예를 들어, FIFO와 다른 대기열 규칙을 사용하여 스레드로부터 안전한 대기열을 만들려면 Queue를 가져오고 Queue.Queue를 하위 클래스로 _get_put 과 같은 메서드를 재정의합니다. "클라이언트 코드는"결코 그 ( "훅") 메소드를 호출 없지만, 같은 아니라 ( "조직") public 메소드 putget (이것은로 알려져 템플릿 메소드 디자인 패턴 - 참조 예를 들어 여기를 기반으로 흥미로운 프리젠 테이션 대본의 시놉시스가 추가된 주제에 대한 내 이야기의 비디오).

편집: 이제 회담 설명의 비디오 링크가 깨졌습니다. 여기여기 에서 처음 두 개의 비디오를 찾을 수 있습니다.


Alex Martelli

._variable 은 반개인적이며 관례를 위한 것입니다.

.__variable 은 종종 superprivate로 잘못 간주되지만 실제 의미는 실수로 액세스하는 것을 방지하기 위해 이름을 변경하는 것입니다. [1]

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

간절히 원하면 .__mangled 변수에 계속 액세스할 수 있습니다. 이중 밑줄은 namemangles 또는 instance._className__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는 이름 변경으로 인해 더 이상 존재하지 않기 때문에 찾을 수 없습니다.

 >>> t._Test__a 'a'

instance._className__variable 액세스하면 숨겨진 값에 액세스할 수 있습니다.


Community Wiki

시작 부분에 단일 밑줄:

Python에는 실제 개인 메서드가 없습니다. 대신 메서드 또는 속성 이름의 시작 부분에 밑줄이 하나 있으면 이 메서드는 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는 "비공개"이므로 액세스해서는 안 됩니다.

시작 부분에 두 개의 밑줄:

이것은 많은 혼란을 야기합니다. 개인 메서드를 만드는 데 사용하면 안 됩니다. 메서드가 하위 클래스에 의해 재정의되거나 실수로 액세스되는 것을 방지하기 위해 사용해야 합니다. 예를 들어 보겠습니다.

 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를 참조하십시오.


Community Wiki

Python에서 밑줄의 의미에 따르면

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

Community Wiki

때때로 다음과 같이 선행 밑줄이 있는 튜플처럼 보이는 것이 있습니다.

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

이 경우 _() 은 로케일에 따라 적절한 언어 등으로 텍스트를 입력하도록 작동하는 로컬라이제이션 함수의 별칭입니다. 예를 들어 Sphinx는 이 작업을 수행하며 수입품 중에서 찾을 수 있습니다.

 from sphinx.locale import l_, _

sphinx.locale에서 _()는 일부 현지화 기능의 별칭으로 할당됩니다.


Community Wiki

많은 사람들이 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

그것은 사실 사생활 보호의 반대입니다. 그것은 모두 자유에 관한 것입니다. 그것 은 당신 의 서브 클래스 가 다른 방법 을 깨뜨리지 않고 한 가지 방법 을 재정 의할 수 있도록 합니다 .

Circle 에서 perimeter 지역 참조를 유지하지 않는다고 가정해 보겠습니다. 이제 파생 클래스 Tire area 를 건드리지 않고 perimeter 의 구현을 재정의합니다. 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 가 필요하지 않습니다.


Community Wiki

변수를 읽기 전용으로 만들고 싶다면 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가 약간 다른 질문을 했다는 것을 이해하지만 '개인 변수를 설정하는 방법'을 묻는 또 다른 질문이 이 질문과 중복되는 것을 발견했기 때문에 여기에 이 추가 정보를 추가할 생각이었습니다.


Community Wiki

단일 선행 밑줄은 규칙입니다. 이름이 하나의 밑줄로 시작하는지 여부는 통역사의 관점에서 볼 때 차이가 없습니다.

__init__ , __bool__ 등과 같은 내장 메서드에 사용됩니다.

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


SilentGhost

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

의미:

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

_some_variable --► 누구나 볼 수 있는 공개이지만 비공개를 나타내는 관례입니다... 경고 파이썬은 시행하지 않습니다.

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

여기에서 정직하게 말하면 Python 문서에 따르면

"객체 내부를 제외하고 액세스할 수 없는 "개인" 인스턴스 변수는 Python에 존재하지 않습니다."

예:

 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)

Community Wiki

다음은 이중 밑줄 속성이 상속된 클래스에 어떻게 영향을 미칠 수 있는지에 대한 간단한 예시입니다. 따라서 다음 설정으로:

 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"

그런 다음 python 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'

이것은 어떤 사람들에게는 분명할 수 있지만 훨씬 더 복잡한 환경에서 나를 당황하게 만들었습니다.


Community Wiki

  • _var : 파이썬에서 선행 단일 밑줄이 있는 변수는 코드를 사용하는 다른 사람들에게 이 변수가 내부 사용을 위해 예약되어야 함을 알리기 위한 고전적인 변수입니다. 그것들은 한 가지 점에서 기존 변수와 다릅니다. 정의된 객체/모듈의 와일드카드 가져오기를 수행할 때 가져오지 않습니다( __all__ 변수 정의 시 예외). 예:

     # foo.py var = "var" _var = "_var"
     # bar.py from foo import * print(dir()) # list of defined objects, contains 'var' but not '_var' print(var) # var print(_var) # NameError: name '_var' is not defined
  • _ : 단일 밑줄은 선행 단일 밑줄 변수의 특수한 경우입니다. 나중에 액세스할 의도가 없는 값을 저장하기 위해 규칙에 따라 휴지통 변수로 사용됩니다. 또한 와일드카드 가져오기로 가져오지 않습니다. 예: for 루프는 "I must not talk in class"를 10번 인쇄하고 _ 변수에 액세스할 필요가 없습니다.

     for _ in range(10): print("I must not talk in class")
  • __var : 이중 선행 밑줄 변수(최소 2개의 선행 밑줄, 최대 1개의 후행 밑줄). 클래스 속성(변수 및 메서드)으로 사용될 때 이러한 변수는 이름 맹글링의 대상이 됩니다. 클래스 외부에서 파이썬은 속성의 이름을 _<Class_name>__<attribute_name> 바꿉니다. 예시:

     class MyClass: __an_attribute = "attribute_value" my_class = MyClass() print(my_class._MyClass__an_attribute) # "attribute_value" print(my_class.__an_attribute) # AttributeError: 'MyClass' object has no attribute '__an_attribute'

    클래스 외부에서 변수로 사용되면 단일 선행 밑줄 변수처럼 작동합니다.

  • __var__ : 이중 선행 및 후행 밑줄 변수(최소 2개의 선행 및 후행 밑줄). 던더스라고도 합니다. 이 명명 규칙은 파이썬에서 내부적으로 변수를 정의하는 데 사용됩니다. 파이썬 업데이트에서 발생할 수 있는 이름 충돌을 방지하기 위해 이 규칙을 사용하지 마십시오. Dunder 변수는 단일 선행 밑줄 변수처럼 작동합니다. 클래스 내에서 사용될 때 이름 맹글링의 대상이 되지 않지만 와일드카드 가져오기에서는 가져오지 않습니다.


Community Wiki

귀하의 질문은 훌륭하며 방법에 관한 것이 아닙니다. 모듈의 함수와 객체는 일반적으로 하나의 밑줄이 접두사로 붙고 접두사 두 개를 사용할 수 있습니다.

그러나 __double_underscore 이름은 예를 들어 모듈에서 이름이 맹글링되지 않습니다. 모듈에서 모두를 가져오면(from module import *) 하나 이상의 밑줄로 시작하는 이름을 가져오지 않고 help(module)에 표시되는 이름도 가져오지 않습니다.


Community Wiki

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

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


Community Wiki

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

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

 _

함수가 예를 들어 API와 같이 공용이 아님을 나타내는 데 사용해야 합니다. 이것과 가져오기 제한으로 인해 C#에서 internal

 __

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

==>

공용이 아닌 것을 나타내려면 protected 사용 _ 처럼 작동해야 합니다. 어떤 것이 공개적으로 사용되지 않는다는 것을 표시하고 싶지만 private 사용 __ .

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

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

하지만 문제는 메서드를 재정의할 때 경고하는 IDE가 없는 경우 실수로 기본 클래스의 메서드를 재정의한 경우 오류를 찾는 데 시간이 걸릴 수 있다는 것입니다.


Community Wiki

메소드의 경우 이중 밑줄을 사용하여 다음 패턴으로 비공개 '메서드'를 숨길 수 있습니다.

 # Private methods of MyClass def _MyClass__do_something(obj:'MyClass'): print('_MyClass__do_something() called. type(obj) = {}'.format(type(obj))) class MyClass(): def __init__(self): __do_something(self) mc = MyClass()

산출:

 _MyClass__do_something() called. type(obj) = <class '__main__.MyClass'>

오늘 클래스 메서드에 이중 밑줄을 사용하려고 시도하고 NameError: name '_<class><method>' is not defined 오류를 얻었을 때 나는 이것을 우연히 발견했습니다.


Community Wiki

출처 : http:www.stackoverflow.com/questions/1301346/what-is-the-meaning-of-single-and-double-underscore-before-an-object-name

반응형