본문 바로가기
Language & Tool/Python

🐍내부에서 작동하는 이중 밑줄 메서드 (+ 네임 맹글링, 단일 밑줄)

by 박수무당벌레 2025. 6. 17.

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로 사용자 코드에서 호출하도록 공개 설계된 함수
  • 복잡한 처리는 내부에 숨기고 외부 사용자가 직접 부르는 간단한 인터페이스 만 노출 ( 안정성과 인터페이스 일관성 보장 )
  • 각 기능을 역할별로 나누기 쉬움