티스토리 뷰
🚀 들어가며...
- 파이썬에서 언더스코어(_, __)는 특별하게 쓰입니다. 타 언어에서 언더스코어(_)는 단지 스네이크 표기법의 변수나 함수명을 위해서만 사용되어지는 반면에 (물론 그렇지 않은 언어도 있습니다.), 파이썬에서의 언더스코어는 의미가 다양합니다. 간단한 예를 들자면, 파이썬 프로그래머라면 for _ in range(10)나 __init__(self)등의 문법들이 굉장히 익숙할 것입니다. 이번 포스트에서는 이 언더스코어(_, __)가 언제 어떤 의미로 쓰이는지에 대해 다루어보려고 합니다. 크게 기술적인 내용은 아니지만 파이썬 프로그래머로서 알아두면 좋을 것 같아 정리해보고자 합니다.
📑 내용
파이썬에서 언더스코어(_)는 다음과 같은 상황에서 사용되는데 크게 5가지의 경우가 있습니다.
- 인터프리터(Interpreter)에서 마지막 값을 저장할 때
- 값을 무시하고 싶을 때 (흔히 “I don’t care"라고 부릅니다.)
- 변수나 함수명에 특별한 의미 또는 기능을 부여하고자 할 때
- 국제화(Internationalization, i18n)/지역화(Localization, l10n) 함수로써 사용할 때
- 숫자 리터럴값의 자릿수 구분을 위한 구분자로써 사용할 때
그럼 이제 각 경우에 대해서 언더스코어(_, __)가 어떻게 쓰이는지 살펴봅시다.
1. 인터프리터에서 사용되는 경우
파이썬 인터프리터에선 마지막으로 실행된 결과값이 _라는 변수에 저장됩니다. 이는 표준 CPython 인터프리터에서 먼저 사용되었으며 다른 파이썬 인터프리터 구현체에서도 똑같이 사용할 수 있습니다.
>>> 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. 특별한 의미의 네이밍을 하는 경우
파이썬에서 _가 가장 많이 사용되는 곳은 아마 네이밍일 것입니다. 파이썬 컨벤션 가이드라인인 PEP8에는 다음과 같은 4가지의 언더스코어를 활용한 네이밍 컨벤션을 소개하고 있습니다.
- _single_leading_underscore: 주로 한 모듈 내부에서만 사용하는 private 클래스/함수/변수/메서드를 선언할 때 사용하는 컨벤션입니다. 이 컨벤션으로 선언하게 되면 from module import *시 _로 시작하는 것들은 모두 임포트에서 무시됩니다. 그러나, 파이썬은 진정한 의미의 private을 지원하고 있지는 않기 때문에 private을 완전히 강제할 수는 없습니다. 즉, 위와 같은 임포트문에서는 무시되지만 직접 가져다 쓰거나 호출을 할 경우엔 사용이 가능합니다. 그래서 “weak internal use indicator"라고 부르기도 합니다.
-
_internal_name = 'one_module' # private 변수 _internal_version = '1.0' # private 변수
- single_trailing_underscore_: 파이썬 키워드와의 충돌을 피하기 위해 사용하는 컨벤션입니다. 그리 많이 사용하지는 않을 것입니다.
-
Tkinter.Toplevel(master, class_='ClassName') # class와의 충돌을 피함 list_ = List.objects.get(1) # list와의 충돌을 피함
- __double_leading_underscores: 이것은 컨벤션이라기보단 하나의 문법적인 요소입니다. 더블 언더스코어는 클래스 속성명을 맹글링하여 클래스간 속성명의 충돌을 방지하기 위한 용도로 사용됩니다. (맹글링이란, 컴파일러나 인터프리터가 변수/함수명을 그대로 사용하지 않고 일정한 규칙에 의해 변형시키는 것을 말합니다.) 파이썬의 맹글링 규칙은 더블 언더스코어로 지정된 속성명 앞에 _ClassName을 결합하는 방식입니다. 즉, ClassName이라는 클래스에서 __method라는 메서드를 선언했다면 이는 _ClassName__method로 맹글링 됩니다. 더블 언더스코어로 지정된 속성명은 위와 같이 맹글링이 되기 때문에 일반적인 속성 접근인 ClassName.__method으로 접근이 불가능합니다. 간혹, 이러한 특징으로 더블 언더스코어를 사용해 진짜 private처럼 보이게 하는 경우가 있는데 이는 private을 위한 것이 아니며 private으로의 사용도 권장되지 않습니다.
-
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'] # 서로 같은 이름의 메서드를 가지지만 오버라이드가 되지 않는다.
- __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
4. 국제화(i18n)/지역화(l10n) 함수로 사용되는 경우
이는 어떤 특정한 문법적 규칙이라기보단 말 그대로 컨벤션입니다. 즉, _가 국제화/지역화 함수라는 의미는 아니며, i18n/l10n 함수를 _로 바인딩하는 C 컨벤션에서 유래된 컨벤션입니다. i18n/l10n 라이브러리인 gettext라는 파이썬 내장 라이브러리 API 문서에서도 이 컨벤션을 사용하고 있으며, i18n과 l10n을 지원하는 파이썬 웹 프레임워크인 Django의 공식 문서에서도 이 컨벤션을 소개하면서 사용하고 있습니다.
# gettext 공식 문서 참고 : https://docs.python.org/3/library/gettext.html
import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print(_('This is a translatable string.'))
from django.utils.translation import ugettext as _
from django.http import HttpResponse
def translate_view(request):
translated = _('This string will be translated.')
return HttpResponse(translated)
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
🙋🏻♂️ 후기
파이썬 언더스코어 포스팅을 하기로 결심하면서 처음에는 싱글 언더스코어와 더블 언더스코어의 차이점 및 사용 예 정도로 간단히 포스팅하려고 했는데 공부를 하다보니 극히 일부만 알고있었던 부분과 새롭게 알게 된 부분(특히 4번과 5번)도 많아서 많이 배웠던 것 같습니다.
잘 정리하여 언더스코어를 남용하는 일이 없도록 잘 개발해야겠습니다.
🔗 참고한 글
https://mingrammer.com/underscore-in-python/
'Python' 카테고리의 다른 글
[python] 함수로 받아온 쿼리 결과를 json 형식으로 만드는 방법 (4) | 2022.09.01 |
---|---|
[python] List Comprehension & Generator (0) | 2022.08.22 |
[python] list 정렬시 특징 정리 (0) | 2022.05.24 |
[python] mutable, immutable 그리고 복사 (0) | 2022.05.23 |
[Python] 파이썬에서 json모듈 다루는 방법 (0) | 2022.05.12 |
- Total
- Today
- Yesterday
- MVT
- uSWGI
- lv2
- list
- django ORM
- django
- Linux
- docker
- SQL
- This
- react
- data formatting
- Python
- container
- Named export
- Default export
- PostgreSQL
- db
- Master & Slave
- 탐욕법
- lv1
- generator expression
- Algorithm
- ORM
- JavaScript
- JS
- programmers
- static files
- Greedy Algorithm
- union-find
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |