underscore _
은 파이썬에서 자주 볼 수 있고 다양하게 사용된다.
주로 인터프리터, 값 무시, 네이밍에 사용된다.
값 무시는 unpacking을 할 때 무시하는 방식을 말한다.
x, _, y = (1, 2, 3)
print(x, y) # 1, 3
a, *_, b = (1, 2, 3, 4, 5)
print(a, b) # 1, 5
a, *i, b = (1, 2, 3, 4, 5) # unpacking
print(a, b, i) # 1, 5, [2, 3, 4]
for _ in range(10):
pass
일반적으로 선언하는 변수는 public하게 선언한다는 의미이다. 언제든 수정할 수 있다. 하지만 underscore을 어떻게 사용하여 변수를 선언하냐에 따라 그 의미가 달라진다.
_variable
: 일반적으로 내부적으로 사용되는 변수나 함수를 나타내는 데 사용한다.
파이썬의 강제적인 규칙은 아니지만 널리 사용되는 약속이다.(사용하면 좋다는 뜻)
_internal_function()
이 있다면, 함수가 내부적으로만 사용되며 외부에서는 사용하지 않기를 권장한다는 의미. 즉, 사용할 순 있지만 강제적이진 않다__variable__
: 파이썬의 특수한 메소드나 속성을 나타낸다. "매직 메소드"라고 주로 부른다. 예를 들어, __init__
, __str__
, __len__
등이 있고 context manager의 __enter__
, __exit__
도 있다.
__variable
: 클래스의 속성을 이름 맹글링(name mangling)을 통해 해당 클래스 내에서만 사용할 수 있도록 하는 데 사용된다. 이는 클래스의 상속 구조에서 속성 이름 충돌을 방지하기 위해 사용된다.
파이썬은 underscore을 통해 public, private 속성을 나타내지만 실제로 접근을 완전히 제한하지 않고 수정하려면 수정할 수 있다.
__variable
이 제한하는 수준은 다음 정도이다.
class TestClass:
def __init__(self):
self.name = Son
self.__age = 30
test = TestClass()
print(test.name) # "Son"
print(test.__age) # AttributeError: 'TestClass' object has no attribute '__age'
print(dir(test))
"""
['_TestClass__age', '__class__', '__delattr__', '__dict__', '__dir__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__',
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']
"""
위 결과처럼 __variable
은 _ClassName__variable
로 바뀌는 것이다. 따라서 접근만 어렵고 수정하려면 할 수 있다.
굳이 이렇게 하는 이유
1.캡슐화 강화: (완벽하진 않더라도) private 속성을 가지기 위함
2.상속 안전성: 클래스 간 상속 시 부모 클래스의 변수를 오버라이딩하는 것을 막아줌 (_ParentClassName__variable
은 하나밖에 없을테니까)
다 뜻이 있다
getter와 setter는 객체의 속성에 대한 접근 및 수정 방법을 제어하는 메소드이다.
Getter는 객체의 특정 속성 값을 검색하는 데 사용된다. 일반적으로 해당 속성에 대한 값을 반환하고 추가적인 계산이나 처리를 수행할 수도 있습니다.
@property
데코레이터를 사용하여 getter 메소드를 정의할 수 있다.
Setter는 객체의 속성 값을 설정하거나 수정하는 데 사용된다. 이 메소드는 새로운 값을 받아 해당 속성에 할당하기 전에 유효성 검사나 추가적인 처리를 수행할 수 있다. 파이썬에서는 @value.setter
데코레이터를 사용하여 setter 메소드를 정의한다.
class MyClass:
def __init__(self, value):
self._value = value
@property
def value(self):
# Getter 메소드
return self._value
@value.setter
def value(self, new_value):
# Setter 메소드 - 여기서 추가적인 유효성 검사를 수행할 수 있음
if new_value < 0:
raise ValueError("Value cannot be negative")
self._value = new_value
cls = MyClass()
print(cls.value) # getter
cls.value = 10 # setter
cls.value = -5 # setter
위를 보면 일반적인 public을 선언하는것과 쓰임새가 달라지는 것이 거의 없어보인다. 실제로 과도한 getter, setter은 가독성을 해치기도 한다.
그래서 위와 같은 유효성 검사를 할 때 사용하는 것이 일반적인 사용방식이다.