1. Python에서 이줄 밑줄 메서드
이름 앞뒤에 __ (언더스코어 두 개)가 붙은 메서드를 의미
→ 매직 메서드(magic method) 또는 특수 메서드(special method)
- __init__, __str__ 등의 __이름__ 형태
- 파이썬 내부에서 특정 동작을 자동으로 수행할 수 있도록 정의된 메서드 ( 특정한 역할을 가진 예약된 이름 )
- 사용자가 직접 호출하지 않더라도 특정 문법이나 연산자에 의해 자동으로 실행 (간접적)
→ ==, +, len() 등의 연산도 이중 밑줄 메서드로 동작
→ 오버라이딩 가능, 사용자가 원하는 방식으로 동작을 정의할 수 있음
class Person:
def __init__(self, name):
self.name = name
def __str__(self):
return f"이름: {self.name}"
p = Person("홍길동")
print(p) # → __str__() 호출됨
※ 앞뒤에 __ 형태는 파이썬이 특정 상황에서 자동 호출하기 위한 메서드 이름 규약으로 임의로 새로운 이중밑줄 메서드를 생성 X, 정의된 것만 사용 권장
2. 주요 이중 밑줄 메서드 (기능별)
- 객체 생성과 소멸 관련
| 설명 | 예시 | 비고 | |
| __init__() | 객체 생성 시 자동 호출되는 생성자 메서드 | obj = ClassName() | 생성자 역할 수행 |
| __del__() | 객체 소멸자 메서드 (소멸 시 자동 호출) | 객체가 소멸될 때 | 호출 시점 예측 불가 |
※ __del__() 사용 주의 사항
- 소멸자 메서드는 파이썬의 메모리 관리 방식(= 가비지 컬렉션, 참조 카운트 기반) 으로 동작하기 떄문에 정확히 호출되는 시점을 알 수 없음
→ 참조가 남아 있는 경우에 소멸 X, 순환 참조가 있는 경우는 del() 호출 없이 객체가 GC에 남을 수 있음
→ 인터프리터 종료시 객체가 여러개 순서 없이 정리되므로 순서 보장이 안 됨
→ 여러 스레드 환경 등 타이밍을 제어하기 어려움
- 리소스 해제용으로 유용, 정확한 시점 제어가 어렵기 때문에 파일 닫기나 DB 연결 종료 같은 작업은 with문 (__enter__, __exit__)을 사용하는 것이 더 안전
- 문자열 표현 및 출력
| 설명 | 예시 | 비고 | |
| __str__() | 문자열로 객체를 표현할 때 호출됨 | print(obj) 또는 str(obj) | - 사용자 친화적인 출력에 활용 - str() 함수와 연동 |
| __repr__() | 개발자용 문자열 반환 (디버깅 목적) | repr(obj) | 객체의 공식 표현 |
- 컨테이너 동작 지원 메서드
| 설명 | 예시 | 비고 | |
| __len__() | 객체의 길이를 구할 때 호출됨 | len(obj) | list, dict, 사용자 정의 컨테이너 등 |
| __getitem__() | 인덱싱 또는 슬라이싱 시 호출됨 | obj[0], obj[1:4] | 시퀀스/매핑 자료형에 자주 사용 |
| __setitem__() | 인덱스에 값 할당 | obj[0] = value | 변경 가능 객체 구현 시 사용 (시퀀스/딕셔너리 자료형 커스터마이징) |
| __delitem__() | 인덱스 삭제 | del obj[0] | 요소 삭제 지원 |
| __contains__() | in 연산자 지원 | 'x' in obj | 포함 여부 정의 |
- 반복자(iterator) 관련
| 설명 | 예시 | 비고 | |
| __iter__() | 반복자 객체 반환 | for x in obj: | 반복 가능 객체 ( 제너레이터 or 클래스 반복자 지원 ) |
| __next__() | 다음 값 반환 (반복자에서 사용됨) | next(obj) | __iter__()와 함께 사용됨 |
- 연산자 오버로딩 (비교/산술)
| 설명 | 예시 | 비고 | |
| __eq__() | 동등 비교 (==) | obj1 == obj2 | |
| __ne__() | 불일치 (!=) | obj1 != obj2 | |
| __lt__() | 작다 (<) | obj1 < obj2 | |
| __le__() | 작거나 같다 (<=) | obj1 <= obj2 | |
| __gt__() | 크다 (>) | obj1 > obj2 | |
| __ge__() | 크거나 같다 (>=) | obj1 >= obj2 | |
| __add__() | 덧셈 (+) | obj1 + obj2 | 문자열/리스트도 활용 가능 |
| __sub__() | 뺄셈 (-) | obj1 - obj2 | |
| __mul__() | 곱셈 (*) | obj1 * obj2 | |
| __truediv__() | 나눗셈 (/) | obj1 / obj2 | |
| __floordiv__() | 정수 나눗셈 (//) | obj1 // obj2 | |
| __mod__() | 나머지 (%) | obj1 % obj2 | |
| __pow__() | 거듭제곱 (**) | obj1 ** obj2 |
- 기타 특수 동작 관련 메서드
| 설명 | 예시 | 비고 | |
| __call__() | 객체를 함수처럼 호출 가능하게 함 | obj() | 함수형 객체 구현 가능 |
| __bool__() |
불리언 평가 (참/거짓 여부 결정) | if obj: | 조건문에서 직접 사용됨 |
- 컨텍스트 매니저 관련 메서드 (with 구문)
| 설명 | 예시 | 비고 | |
| __enter__() | with 문 진입 시 실행 | with obj: | 자원 할당 (파일, DB 연결 등) |
| __exit__() | with 문 종료 시 실행 | with obj: | 리소스 해제, 예외 처리 등 |
3. 네임 맹글링(Name Mangling)
비공개의 의미를 담은 변수 이름을 정의하기 위해 클래스 내부의 변수/함수 이름 앞에 이중 밑줄을 붙여 암묵적으로 전달
→ Python에서는 접근 제한자(private 등) 키워드가 존재하지 않기 때문에 접두어 규칙 사용
- __secret, __inorder 처럼 쓰임 (앞에만 밑줄 2개)
- __변수명 이중 밑줄을 붙이면, Python에서 내부적으로 변수/함수 이름을 _클래스명__변수명 으로 자동으로 변경 (네임 맹글링)
- 외부 접근 방지 + 서브클래스 오버라이딩 (상속 관계 이름 충돌) 방지
→ 완전한 캡슐화는 아니지만 내부용이라고 명시적 표현
→ 외부에서 __변수명 만으로 호출하면 에러 발생
→ 단, 내부적으로 바뀐 이름을 통해 호출은 가능 ex) obj._MyClass__hidden_method() - 비공개 메서드/속성, 상속 충돌 방지 등의 목
class MyClass:
def __init__(self):
self.__secret = "비밀"
def __hidden_method(self):
print("숨겨진 메서드")
def call(self):
self.__hidden_method()
obj = MyClass()
print(obj.__secret) # X, AttributeError 에러
obj.__hidden_method() # X, AttributeError 에러
# 정상 출력
print(obj._MyClass__secret)
obj.call()
obj._MyClass__hidden_method() # 가능
4. 비공식 내부용 약속 (단일 밑줄)
함수명 (또는 변수명)에 밑줄 하나 _ 가 앞에 붙는 경우, 내부용 이라는 비공식적 접근 제한
→ 지정한 변수/함수는 내부에서만 사용되는 것이며, 외부에서는 사용하지 마세요 라는 개발자 간의 약속
→ private 보다는 protected 와 유사 ( 약속상 내부 전용, 외부 호출은 가능하지만 지양 )
- _helper(), _internal_var 처럼 _이름 으로 표현 (앞에 밑줄 1개)
- 비공개(내부용) 메서드 관례(Convention) (암묵적)
- 실제로 접근 제한은 없음, 코드 구조상 내부에서만 사용되도록 표현함
→ 강제성 없음, 그냥 의미 있는 관례(= 외부 호출 지양)
→ 네임 맹글링 X, 내부에서 이름 변경도 없음
→ 자식 클래스에서 덮어쓰기(override) 가능 - 모듈 외부 공개 차단 (from module import *) 목적, 혹은 내부 전용으로 로직 분리를 위해 쓰임
→ 모듈 import 하는 경우, _ 로 시작한 변수는 제외됨
→ 사용자에겐 update 하는 함수만 제공하고 재귀 호출, 복잡한 매개변수 처리, lazy logic 등을 숨기는 내부 처리 용으로서 _를 붙인 함수를 씀
내부 함수, 즉 외부에서 직접 호출하지 않도록 의도한 비공개용 함수이자 숨겨진 헬퍼 함수(internal helper) - (일시적으로) 사용하지 않음을 표시하는 등 다른 용례도 있음 ※ 아래에 추가 설명
→ 결과를 무시하거나 이름 없는 변수로 쓰는 경우 ex) _ = some_func()
class MyClass:
def __init__(self):
self._internal_data = 123
obj = MyClass()
print(obj._internal_data) # 출력은 됨 (하지만 원래는 내부용)
- 단일 밑줄의 다른 용례/목적
| 형태 | 용도 | 설명 | |
| 내부용 이름 | _variable | 보호용(Protected) 관례 | 외부 사용을 지양하라는 의미 (접근 제한 X) |
| 모듈 import 제어 | __all__ = [...] | 공개 API 지정 | from module import * 시 가져올 항목 명시 |
| 무시용 | _ = something | 변수 무시 | 값 무시용 변수 |
| 루프용 | for _ in range(n) | 반복만 하고 값은 무시 | 인덱스를 쓰지 않을 때 ( 반복 인덱스 무시 ) |
| 마지막 값 | _ (인터프리터에서) | 마지막 계산 결과 | Python REPL에서 _는 마지막 결과 저장 |
| 국제화용 | _('text') | gettext alias | 다국어 처리(i18n)에서 _()는 번역 함수로 자주 사용 |
| 이름 충돌 회피 | _1, _temp | 중복 피하기 | 짧은 생명주기용 변수명에 사용 (보통 임시 변수) |
| unpack 무시 | a, _, b = (1, 2, 3) | 일부 값 무시 | 여러 값 중 필요 없는 항목 무시 |
- 밑줄 없는 함수와의 연동
- 밑줄이 없는 경우, 공식적인 외부용 API로 사용자 코드에서 호출하도록 공개 설계된 함수
- 복잡한 처리는 내부에 숨기고 외부 사용자가 직접 부르는 간단한 인터페이스 만 노출 ( 안정성과 인터페이스 일관성 보장 )
- 각 기능을 역할별로 나누기 쉬움
'Language & Tool > Python' 카테고리의 다른 글
| 🐍반복 처리를 위한 itertools, more_itertools (1) | 2025.06.20 |
|---|---|
| 🌱논리 연산과 비트 연산(Python) (1) | 2025.06.18 |
| 🐍정밀 소수점 제어 모듈, decimal (1) | 2025.06.17 |
| 🐍배열, 행렬 기반의 numpy (0) | 2025.06.17 |
| 🐍연산자 함수화, operator 모듈 (0) | 2025.06.16 |