파이썬에서 객체 이름 앞에 밑줄이 있다는 정확한 의미와 둘의 차이점을 설명해 주시겠습니까?
또한 문제의 대상이 변수, 함수, 방법 등인지 여부가 동일하게 유지됩니까?
답변
단일 밑줄
클래스에서 밑줄이있는 이름은 단순히 다른 프로그래머에게 속성 또는 메소드가 개인용임을 나타 내기위한 것입니다. 그러나 이름 자체로는 특별한 것이 없습니다.
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!'}
답변
지금까지는 훌륭한 답변을 받았지만 약간의 허기가 없습니다. 하나의 주요 밑줄이 정확히되지 않습니다 단지 컨벤션 : 당신이 사용하는 경우 from foobar import *
, 및 모듈 foobar
정의하지 않는 __all__
목록을 모듈에서 가져온 이름이 없는 최고의 밑줄있는 사람을 포함한다. 이 경우는 꽤 모호한 코너이기 때문에 대부분 컨벤션 이라고 가정 해 봅시다 .-).
선행 밑줄 규칙은 널리 단지에 사용되는 개인 이름뿐만 아니라 C ++에서라고 부르는 대한 보호 예를 들어, 완전히 의도 된 방법의 이름은 서브 클래스 (심지어 사람에 의해 오버라이드 (override) 할 수 – 사람을 가지고 에 있기 때문에 오버라이드 (override) 할 수 기본 클래스 (들) raise NotImplementedError
!-)는 종종 해당 클래스 (또는 서브 클래스)의 인스턴스를 사용하여 코드 에 해당 메소드가 직접 호출되지 않는다는 것을 나타내는 단일 밑줄 이름 입니다.
예를 들어, FIFO 큐가 아닌 다른 분야와 스레드 안전 큐 있도록 한 수입 대기열 Queue.Queue 서브 클래스와 같은 방법을 대체 _get
하고 _put
; “클라이언트 코드는”결코 그 ( “훅”) 메소드를 호출 없지만, 같은 아니라 ( “조직”) public 메소드 put
와 get
(이것은로 알려져 템플릿 메소드 디자인 패턴 – 예를 들어, 참조 여기에 비디오를 기반으로 흥미로운 프리젠 테이션 성적표의 개요를 추가하여 주제에 대한 나의 이야기에 대한 이야기).
편집 : 대화 설명의 비디오 링크가 끊어졌습니다. 처음 두 비디오는 여기 및 여기 에서 찾을 수 있습니다 .
답변
__foo__
: 이것은 단지 규칙이며, 파이썬 시스템이 사용자 이름과 충돌하지 않는 이름을 사용하는 방법입니다.
_foo
: 이것은 단지 관습에 불과합니다. 프로그래머가 변수가 개인임을 나타냅니다 (파이썬에서 의미하는 것).
__foo
: 이것은 실제 의미를 갖습니다. 인터프리터는이 이름을 _classname__foo
다른 클래스에서 유사한 이름과 겹치지 않도록하기 위해이 이름을 바꿉니다 .
파이썬 세계에서 다른 형태의 밑줄은 의미가 없습니다.
이 규칙에서 클래스, 변수, 전역 등의 차이점은 없습니다.
답변
._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
대신 이중 밑줄 이름, 당신은 숨겨진 값에 액세스 할 수 있습니다
답변
처음에 단일 밑줄 :
파이썬에는 실제 개인 메소드가 없습니다. 대신, 메소드 또는 속성 이름 시작시 밑줄 하나는 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를 참조하십시오 .
답변
때로는 다음과 같이 밑줄이있는 튜플 인 것처럼 보입니다.
def foo(bar):
return _('my_' + bar)
이 경우 진행중인 작업은 _ ()가 로캘을 기반으로 올바른 언어 등으로 텍스트를 입력하는 텍스트에서 작동하는 지역화 함수의 별칭입니다. 예를 들어, 스핑크스는이 작업을 수행하며 수입품 중
from sphinx.locale import l_, _
sphinx.locale에서 _ ()는 일부 지역화 함수의 별칭으로 할당됩니다.
답변
많은 사람들이 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
. 이제 파생 클래스 Tire
는 perimeter
을 터치하지 않고 의 구현을 재정의합니다 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
.
