파이선 도큐멘테이션을 보다가 변수 _
에 대한 예시가 나왔다.
n [23]: tax = 12.5 /100
In [24]: price = 100.50
In [25]: price * tax
Out[25]: 12.5625
In [26]: price + _
Out[26]: 113.0625
In [27]: round(_, 2)
Out[27]: 113.06
살펴 보니 이 예제에서 _
언더스코어는 , 마지막 변수를 저장하는 역할을 한다.
문득, 파이썬에서 _
는 __init__
, __func1
, 등 여러 곳에서 쓰이고 있는 것을 알수 있지만 정작 어떤 역할을 하는지 어떤 문법적 의미인지 잘 모르고 있었다.
있는 듯 없는 존재?
이번 기회에 블러거 님들이 정리해 둔 것을 참고로 삼아 지금은 잘 모르더라도 우선 집고 넘어가 보기로 한다.
mingrammer, corikachu, Y.LAB , Sanghee Lee 님들의 블로그 글을 참고 했다.
파이썬에서 언더스코어(_) 쓰임새는 크게 5가지의 경우로 나눌 수 있다.
-
인터프리터(Interpreter)에서 마지막 값을 저장할 때
-
값을 무시하고 싶을 때 (특정값을 skip 할때)
-
변수나 함수명에 특별한 의미 또는 기능을 부여하고자 할 때
-
국제화(Internationalization, i18n)/지역화(Localization, l10n) 함수로써 사용할 때 (WHat?)
-
숫자 리터럴값의 자릿수 구분을 위한 구분자로써 사용할 때
이런… 잘 모르겠다(?_?) 자세한 설명과 예시가 필요하다.
1. 인터프리터에서 사용되는 경우
바로 위의 예시처럼 파이썬(ipython) 인터프리터에서 마지막 실행된 결과값이 _
라는 변수에 저장이 된다.
또 다른 예시
>>> 10
10
>>> _
10
>>> _ * 3
30
>>> _ * 20
600
2. 값을 무시하고 싶은 경우
_
는 어떤 특정 값을 무시하기 위한 용도로 사용되기도 한다. 값이 필요하지 않거나 사용되지 않는 값을 _
에 할당하기만 하면된다.
# 언패킹시 특정값을 무시
x, _, y = (1, 2, 3) # x = 1, y = 3
# 여러개의 값 무시
x, *_, y = (1, 2, 3, 4, 5) # x = 1, y = 5
# 인덱스 무시
for _ in range(10):
do_something()
# 특정 위치의 값 무시
for _, val in list_of_tuple:
do_something()
3. 특별한 의미의 네이밍을 하는 경우
이제껏 내가 가장 많이 썼던 _
의 용도 일 것이다.
언더스코어 네이밍은 주로 파이썬에서 public, private을 구분하기 위한 용도로 많이 사용한다.
__
더블언더스코어로 멤버 변수나 멤버 함수를 선언하게 되면, private 처럼 동작한다.
모듈로써 다른 곳에서 사용할 경우에 import가 되지 않는다.
# 더블 언더스코어 사용 시, private처럼 활용 가능.
class HasPrivate:
def __init__(self):
self.public = "Public"
self.__private = "Private"
def print_from_internal(self):
print(self.public)
print(self.__private)
def public_print(self):
print("public print")
self.__private_print()
def __private_print(self):
print("private print")
obj = HasPrivate()
obj.print_from_internal()
print(obj.public)
print(obj.__private) # error
obj.public_print()
obj.__private_print() # error
# 다른 모듈에서는 `_` 만 해줘도 접근 불가능!
_
언더스코어를 활용한 네이밍 컨벤션 방법
- 1-1.
_single_leading_underscore
: 주로 한 모듈 내부에서만 사용하는 private 클래스/함수/변수/메서드를 선언할 때 사용하는 컨벤션이다. 이 컨벤션으로 선언하게 되면from module import *
시_
로 시작하는 것들은 모두 임포트에서 무시된다. 그러나, 파이썬은 진정한 의미의 private을 지원하고 있지는 않기 때문에 private을 완전히 강제할 수는 없다. 즉, 위와 같은 임포트문에서는 무시되지만 직접 가져다 쓰거나 호출을 할 경우엔 사용이 가능하다. 그래서 “weak internal use indicator”라고 부르기도 한다.
_internal_name = 'one_module' # private 변수
_internal_version = '1.0' # private 변수
class _Base: # private 클래스
_hidden_factor = 2 # private 변수
def __init__(self, price):
self._price = price
def _double_price(self): # private 메서드
return self._price * self._hidden_factor
def get_double_price(self):
return self._double_price()
- 1-2.
single_trailing_underscore_
: 파이썬 키워드와의 충돌을 피하기 위해 사용하는 컨벤션이다. 그리 많이 사용하지는 않을 것이다.
Tkinter.Toplevel(master, class_='ClassName') # class와의 충돌을 피함
list_ = List.objects.get(1) # list와의 충돌을 피함
- 1-3.
__double_leading_underscores
: 이는 컨벤션이라기보단 하나의 문법적인 요소이다.__
더블 언더스코어는 클래스 속성명을 맹글링하여 클래스간 속성명의 충돌을 방지하기 위한 용도로 사용된다. (맹글링이란, 컴파일러나 인터프리터가 변수/함수명을 그대로 사용하지 않고 일정한 규칙에 의해 변형시키는 것을 말한다.) - 파이썬의 맹글링 규칙은 더블 언더스코어로 지정된 속성명 앞에
_ClassName
을 결합하는 방식이다. 즉, ClassName이라는 클래스에서__method
라는 메서드를 선언했다면 이는_ClassName__method
로 맹글링 된다.
class A:
def _single_method(self):
pass
def __double_method(self): # 맹글링을 위한 메서드
pass
class B(A):
def __double_method(self): # 맹글링을 위한 메서드
pass
print(dir(A())) # ['_A_double_method', ..., '_single_method']
print(dir(B())) # ['_A_double_method', '_B_double_method', ..., '_single_method']
# 서로 같은 이름의 메서드를 가지지만 오버라이드가 되지 않는다.
__
더블 언더스코어로 지정된 속성명은 위와 같이 맹글링이 되기 때문에 일반적인 속성 접근인 ClassName.__method
으로 접근이 불가능하다. 간혹, 이러한 특징으로 더블 언더스코어를 사용해 진짜 private처럼 보이게 하는 경우가 있는데 이는 private을 위한 것이 아니며 private으로의 사용도 권장되지 않는다.
Python 문서에서 부연 설명으로
“But try to avoid the
__private
form. I never use it. Trust me. If you use it, you WILL regret it later.”(이 양식을 사용하면 나중에 꼭 후회한다고 경고아닌 경로를 주고 있다. - 그러면 왜 만들었을까? )
-
1-4.
__double_leading_and_trailing_underscores__
: 스페셜 변수나 메서드(매직 메서드라고도 부른다.)에 사용되는 컨벤션이며,__init__
,__len__
과 같은 메서드들이 있다. 이런 형태의 메서드들은 어떤 특정한 문법적 기능을 제공하거나 특정한 일을 수행한다.__file__
은 현재 파이썬 파일의 위치를 나타내는 스페셜 변수__eq__
은a == b
라는 식이 수행될 때 실행되는 스페셜 메서드이다.__init__
의 경우 클래스의 인스턴스가 생성될 때 처음으로 실행되는 메서드인데 인스턴스의 초기화 작업을 이 메서드의 내용으로 작성할 수 있다.- 물론 사용자가 직접 만들 수도 있지만 그런 경우는 정말 거의 없으며, 일부 스페셜 메서드의 경우 직접 수정하거나 하는 일은 빈번히 있을 수 있다.
class A:
def __init__(self, a): # 스페셜 메서드 __init__에서 초기화 작업을 한다.
self.a = a
def __custom__(self): # 커스텀 스페셜 메서드. 이런건 거의 쓸 일이 없다.
pass
-
- 1-5. 국제화 (internationalization, I18N), 현지화 (localization, L10N), 혹은 다국어화(multilingualization, m17n) 함수로 사용되는 경우
gettext
파이썬 내장 라이브러리 API-
gettext.py
: source code
# gettext 공식 문서 참고 : https://docs.python.org/3/library/gettext.html
# Lib / gettext.py : https://github.com/python/cpython/blob/3.6/Lib/gettext.py
import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print(_('This is a translatable string.'))
django documentaion - translation
# https://docs.djangoproject.com/en/2.0/topics/i18n/translation/
from django.utils.translation import gettext as _
from django.http import HttpResponse
def my_view(request):
output = _("Welcome to my site.")
return HttpResponse(output)
5. 숫자 리터럴값의 자릿수 구분을 위한 구분자로써 사용할 때
Python 3.6에 추가된 문법으로 언더스코어로 숫자값을 좀 더 읽기 쉽도록 자릿수를 구분할 수 있게 되었다.
dec_base = 1_000_000
bin_base = 0b_1111_0000
hex_base = 0x_1234_abcd
print(dec_base) # 1000000
print(bin_base) # 240
print(hex_base) # 305441741
파이썬에서 사용되는 _
의 의미는 무척 다양하다. 코드를 짜보면서 내용들을 익혀나가면 좋겠다.
다음 번에는 내친김에 __
더블언더 스코어 , 매직매서드를 공부해 보도록 하자.