파이썬에서 객체 이름 앞에 밑줄이 있다는 정확한 의미와 둘의 차이점을 설명해 주시겠습니까?
또한 문제의 대상이 변수, 함수, 방법 등인지 여부가 동일하게 유지됩니까?
파이썬에서 객체 이름 앞에 밑줄이 있다는 정확한 의미와 둘의 차이점을 설명해 주시겠습니까?
또한 문제의 대상이 변수, 함수, 방법 등인지 여부가 동일하게 유지됩니까?
답변:
클래스에서 밑줄이있는 이름은 단순히 다른 프로그래머에게 속성 또는 메소드가 개인용임을 나타 내기위한 것입니다. 그러나 이름 자체로는 특별한 것이 없습니다.
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!'}
__
변수 이름으로 단순히 이중 밑줄 의 의미는 무엇 입니까? 처럼a, __ = foo()
지금까지는 훌륭한 답변을 받았지만 약간의 허기가 없습니다. 하나의 주요 밑줄이 정확히되지 않습니다 단지 컨벤션 : 당신이 사용하는 경우 from foobar import *
, 및 모듈 foobar
정의하지 않는 __all__
목록을 모듈에서 가져온 이름이 없는 최고의 밑줄있는 사람을 포함한다. 이 경우는 꽤 모호한 코너이기 때문에 대부분 컨벤션 이라고 가정 해 봅시다 .-).
선행 밑줄 규칙은 널리 단지에 사용되는 개인 이름뿐만 아니라 C ++에서라고 부르는 대한 보호 예를 들어, 완전히 의도 된 방법의 이름은 서브 클래스 (심지어 사람에 의해 오버라이드 (override) 할 수 - 사람을 가지고 에 있기 때문에 오버라이드 (override) 할 수 기본 클래스 (들) raise NotImplementedError
!-)는 종종 해당 클래스 (또는 서브 클래스)의 인스턴스를 사용하여 코드 에 해당 메소드가 직접 호출되지 않는다는 것을 나타내는 단일 밑줄 이름 입니다.
예를 들어, FIFO 큐가 아닌 다른 분야와 스레드 안전 큐 있도록 한 수입 대기열 Queue.Queue 서브 클래스와 같은 방법을 대체 _get
하고 _put
; "클라이언트 코드는"결코 그 ( "훅") 메소드를 호출 없지만, 같은 아니라 ( "조직") public 메소드 put
와 get
(이것은로 알려져 템플릿 메소드 디자인 패턴 - 예를 들어, 참조 여기에 비디오를 기반으로 흥미로운 프리젠 테이션 성적표의 개요를 추가하여 주제에 대한 나의 이야기에 대한 이야기).
편집 : 대화 설명의 비디오 링크가 끊어졌습니다. 처음 두 비디오는 여기 및 여기 에서 찾을 수 있습니다 .
_var_name
또는 사용 var_name
+에서 제외 __all__
?
__all__
하여 모듈을 from spam import *
친숙 하게 만들 때마다 명시 적으로 사용하십시오 . 따라서 대부분의 경우 대답은 둘 다 입니다.
_
private을 호출하면 싫어합니다 . 분명히 파이썬에서 사적인 것이 없기 때문에 유추에 대해 이야기하고 있습니다. 의미로 다이빙 나는 우리가를 묶을 수라고 말하고 싶지만 때 _
자바로 보호 하기 때문에 proctected 자바 수단 "파생 클래스 및 / 또는 같은 패키지 내". PEP8은 이미 수입품 _
에 대해 이야기 할 때 관습이 아니라고 알려주므로 패키지로 모듈을 교체하십시오 *
. 클래스 내에서 식별자에 대해 말할 때 __
Java의 개인 과 확실히 동일합니다 .
__foo__
: 이것은 단지 규칙이며, 파이썬 시스템이 사용자 이름과 충돌하지 않는 이름을 사용하는 방법입니다.
_foo
: 이것은 단지 관습에 불과합니다. 프로그래머가 변수가 개인임을 나타냅니다 (파이썬에서 의미하는 것).
__foo
: 이것은 실제 의미를 갖습니다. 인터프리터는이 이름을 _classname__foo
다른 클래스에서 유사한 이름과 겹치지 않도록하기 위해이 이름을 바꿉니다 .
파이썬 세계에서 다른 형태의 밑줄은 의미가 없습니다.
이 규칙에서 클래스, 변수, 전역 등의 차이점은 없습니다.
__foo
궁금했다. 다른 클래스와 유사한 메소드 이름과 어떻게 겹칠 수 있습니까? 나는 여전히 instance.__foo()
(통역사가 이름을 바꾸지 않은 경우) 계속 액세스해야한다는 것을 의미 합니까?
B
서브 클래스 A
하고 둘 다 구현 하면 상속 된 from foo()
을 B.foo()
재정의합니다 . 의 인스턴스는 via를 제외하고 만 액세스 할 수 있습니다 . .foo()
A
B
B.foo()
super(B).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를 참조하십시오 .
많은 사람들이 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
.
변수를 읽기 전용으로 만들고 싶다면 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는 약간 다른 질문을했지만 이해하기 쉬운 '개인 변수를 설정하는 방법'을 묻는 다른 질문을 발견했기 때문에 여기에 추가 정보를 추가하려고 생각했습니다.
에 Accroding https://dbader.org/blog/meaning-of-underscores-in-python
훌륭한 답변과 모든 것이 정확합니다. 나는 간단한 정의 / 의미와 함께 간단한 예를 제공했습니다.
의미:
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)
귀하의 질문은 좋습니다. 단지 방법에 관한 것이 아닙니다. 모듈의 함수와 객체는 일반적으로 하나의 밑줄로 시작하며 두 개의 접두사가 붙을 수 있습니다.
그러나 __double_underscore 이름은 예를 들어 모듈에서 이름이 표시되지 않습니다. 모듈에서 모든 모듈을 가져 오거나 (모듈 가져 오기 *에서) 이름이 help (module)에 표시되지 않으면 하나 이상의 밑줄로 시작하는 이름은 가져 오지 않습니다.
다음은 이중 밑줄 속성이 상속 된 클래스에 영향을 줄 수있는 간단한 예입니다. 따라서 다음 설정으로
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'
이것은 일부에게는 분명 할 수 있지만 훨씬 더 복잡한 환경에서 나를 경계하게했습니다.
객체 내부를 제외하고는 액세스 할 수없는“비공개”인스턴스 변수는 Python에 없습니다. 그러나 대부분의 Python 코드가 따르는 규칙이 있습니다. 밑줄 (예 : _spam)이 접두어로 붙은 이름은 API의 비공개 부분으로 간주되어야합니다 (함수, 메소드 또는 데이터 멤버인지 여부) . 구현 세부 사항으로 간주되며 예고없이 변경 될 수 있습니다.
참조 https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
_와 __의 사실을 얻는 것은 매우 쉽습니다. 다른 답변들은 그것들을 꽤 잘 표현합니다. 사용법을 결정하기가 훨씬 어렵습니다.
이것이 내가 보는 방법입니다.
_
함수가 API와 같이 공용으로 사용되지 않음을 나타 내기 위해 사용해야합니다. 이것과 가져 오기 제한으로 인해 internal
C # 에서처럼 동작합니다 .
__
상속 계층 구조에서 이름 충돌을 피하고 지연을 피하기 위해 사용해야합니다. C #의 private과 매우 유사합니다.
==>
무언가가 공개용이 아니라는 것을 나타내려면 use처럼 작동해야 protected
합니다 _
. 무언가가 공용이 아니라고 표시하고 싶지만 사용하는 것처럼 행동해야 private
합니다.__
.
이것은 또한 내가 매우 좋아하는 인용문입니다.
문제는 클래스 작성자가 "이 속성 / 메소드 이름은 비공개 여야하고이 클래스 정의 내에서만 액세스 할 수 있어야합니다"라고 합법적으로 생각하고 __private 규칙을 사용할 수 있다는 것입니다. 그러나 나중에 해당 클래스의 사용자는 해당 이름에 합법적으로 액세스해야하는 서브 클래스를 만들 수 있습니다. 따라서 수퍼 클래스를 수정해야하거나 (어려울 수도 있고 불가능할 수도 있음) 서브 클래스 코드는 수동으로 맹 글링 된 이름을 사용해야합니다 (최악하고 깨지기 쉬운).
그러나 문제는 메소드를 재정의 할 때 경고하는 IDE가 없으면 기본 클래스의 메소드를 실수로 재정의 한 경우 오류를 찾는 데 시간이 걸릴 수 있다고 생각합니다.