프로젝트를 진행하다가 _를 잘 모르고 있다는 사실을 발견했다.
용례를 찾아보던 중 무척 잘 정리되어 있는 블로그를 발견했다.
언더스코어 사용 사례 정리왕 버전
미래의 나를 위해 남겨 두자면
>>> 1+1
2
>>> _+1
3
이런식이다. 숫자만 가능한 것이 아니고 문자열, 인스턴스 등 다양한 형태의 저장이 가능하다.
>>> t = 1,2,3,4,5 #튜플 작성시 괄호 생략 가능하다.
>>> a, b, c, _, e = t
>>> print(a, b, c, e)
1 2 3 5
# 여기서 _의 값이 4로 출력되기는 한다.
>>> n = 100_000_000
>>> print(n)
100000000
네이밍
(1) _ 가 이름 앞쪽에 한 개만 붙은 경우(_foo) : 모듈 내에서만 사용하겠다는 의미
import * 로 해당 모듈을 import 할 수 없다. 하지만 Private하게 사용하겠다는 의미를 주는 것일 뿐, 완전히 Private하게 만드는 역할을 하는 것은 아니기 때문에 import _a처럼 이름을 명기하여 호출하면 다른 모듈에서도 사용할 수 있다.
(2) _ 가 이름 뒤쪽에 하나 붙은 경우 (foo_) : 파이썬 키워드와의 충돌을 피하기 위해 사용
built in 함수나, 예약어 등 파이썬 키워드와 변수/함수명의 충돌을 피하기 위해 사용한다.
(3) _ 이름 앞에 언더바가 두 개 붙은 경우(__foo) : 문법적 요소의 하나, '네임맹글링'을 위함
네임맹글링이란 뭘까?
파이썬은 이름 앞에 언더바를 __두개 붙인 변수/함수의 이름을 일정한 규칙을 갖고 자동으로 변화시켜준다. 여기서 적용되는 일정한 규칙은 '_클래스명__속성명'이다.
네임맹글링이 왜 필요한가?
크게 두 가지 경우에 필요한데,
1. 클래스의 속성값을 외부에서 접근하기 힘들게 할 때(Private한 속성을 더함. dir()로 접근할 수 있기 때문에 완벽한 private는 아님)
2. 하위 클래스가 상위 클래스의 속성을 오버라이딩하는 것을 막을 때 이다.
# 예시 1
class TestClass():
def __init__(self):
self.name = '감자'
self.color = '갈색'
self.__size = '1kg'
potato = TestClass()
print(potato.name) # 감자
print(potato.color) # 갈색
print(potato.__size) # AttributeError: 'TestClass' object has no attribute '__size'
위의 코드와 같이 __를 이용해 네임맹글링을 해주면 감자의 size속성을 외부에서는 쉽게 접근할 수 없다. 다만 dir() : 특정한 함수의 모든 요소를 반환하는 함수를 이용하면 맹글링된 이름을 볼 수 있다.
# 예시2
class TestClass():
def __init__(self):
self.name = '감자'
self.color = '갈색'
self.__size = '1kg'
class TestClass2(TestClass):
def __init__(self):
self.name = '감자'
self.color = '감자색'
self.__size = '3kg'
potato = TestClass2()
print(potato.name, potato.gender, potato.__size)
AttributeError: 'TestClass2' object has no attribute '__size'
예시 2의 경우, 파이썬이 맹글링을 할 때, _클래스명__속성명을 함께 사용하기 때문에 TestClass의 __size가 오버라이드 되지 않고, TestClass2의 __size와 별개로 존재한다.
(4) 앞 뒤로 언더바가 2개씩 붙는 경우(ex: foo)__파이썬에 내장된 특수한 함수와 변수를 나타낼 때 사용. 오버라이딩할 때 사용.
매직 메소드, 던더 메소드(Dunder Method)라고 불림.
가장 대표적으로 인스턴스 생성시 실행되는 생성자 역할을 하는 __init__
우선은 정리 끝!