
파이썬에서 클래스를 정의하고 인스턴스를 생성할 때, 대부분의 개발자는 __init__ 메서드가 가장 먼저 호출된다고 생각합니다. 하지만 파이썬의 객체 생성 매커니즘은 생각보다 정교하며, 실제로는 생성(Construction)과 초기화(Initialization)라는 두 가지 명확한 단계로 나뉩니다. 이 과정을 이해하는 것은 싱글톤 패턴 구현, 불변 객체(Immutable Object) 커스텀, 또는 메타프로그래밍을 다루는 시니어 개발자에게 필수적인 지식입니다. 본 글에서는 __new__와 __init__의 내부 동작 차이를 완벽하게 분석합니다.
1. 객체 생성의 타임라인: 누가 먼저인가?
파이썬에서 obj = MyClass()를 실행하면 내부적으로 두 개의 매직 메서드가 순차적으로 호출됩니다. 첫 번째는 메모리 공간을 할당하고 실제 객체를 만드는 __new__이며, 두 번째는 만들어진 객체에 속성값을 부여하는 __init__입니다.
2. __new__ vs __init__ 핵심 비교 분석
두 메서드의 역할과 특성을 한눈에 비교할 수 있도록 표로 정리했습니다.
| 주요 역할 | 객체의 실제 생성 (메모리 할당) | 생성된 객체의 초기화 (상태 설정) |
| 호출 순서 | 1순위 (가장 먼저 실행) | 2순위 (__new__ 이후 실행) |
| 메서드 타입 | 정적 메서드 (Static Method 개념) | 인스턴스 메서드 (Instance Method) |
| 반환값 | 생성된 인스턴스를 반드시 반환 | 반환값이 없음 (내부적으로 None 반환) |
| 첫 번째 인자 | cls (클래스 자신) | self (생성된 인스턴스) |
3. __new__를 반드시 조작해야 하는 3가지 상황
일반적인 프로그래밍에서는 __init__만으로 충분하지만, 다음과 같은 방법이 필요할 때는 __new__를 오버라이딩해야 합니다.
첫째, 불변 객체(Immutable Types)의 상속
int, str, tuple과 같은 불변 객체는 이미 생성된 후에 값을 변경할 수 없습니다. 따라서 이들을 상속받아 값을 변형한 서브 클래스를 만들려면 __init__이 아닌, 객체가 생성되는 시점인 __new__에서 값을 결정해야 합니다.
둘째, 싱글톤(Singleton) 패턴의 구현
애플리케이션 전체에서 단 하나의 인스턴스만 존재해야 하는 경우, __new__ 메서드 내에서 기존에 생성된 인스턴스가 있는지 확인하고, 있다면 새로 생성하지 않고 기존 인스턴스를 반환하도록 제어할 수 있습니다.
셋째, 메타프로그래밍과 프레임워크 설계
객체가 생성되기 직전에 가로채서 로깅을 남기거나, 특정 조건에 따라 다른 클래스의 인스턴스를 반환하는 등 동적인 객체 생성이 필요할 때 사용됩니다.
4. Sample Example: 싱글톤 패턴과 실행 순서 확인
아래 코드는 __new__와 __init__이 실행되는 순서를 증명하고, 이를 이용해 싱글톤 객체를 만드는 해결 방법을 보여줍니다.
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
print("1. __new__ 호출: 인스턴스를 생성합니다.")
if cls._instance is None:
# 부모 클래스인 object의 __new__를 호출하여 실제 메모리 할당
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, name):
print(f"2. __init__ 호출: {name}으로 초기화합니다.")
self.name = name
# 두 번의 인스턴스 생성 시도
obj1 = Singleton("첫 번째")
obj2 = Singleton("두 번째")
print(f"obj1 name: {obj1.name}")
print(f"obj2 name: {obj2.name}")
print(f"두 객체는 동일한가? {obj1 is obj2}")
# [출력 결과]
# 1. __new__ 호출...
# 2. __init__ 호출... (첫 번째)
# 1. __new__ 호출... (기존 인스턴스 반환)
# 2. __init__ 호출... (두 번째로 덮어씌워짐)
# 두 객체는 동일한가? True
5. 개발자가 자주 범하는 실수와 주의점
- 반환값 누락:
__new__에서 인스턴스를 반환하지 않으면__init__은 절대 실행되지 않습니다.super().__new__(cls)를 호출하는 것을 잊지 마세요. - __init__의 반복 호출: 싱글톤 구현 시
__new__가 동일한 인스턴스를 반환하더라도, 파이썬은 매번__init__을 호출합니다. 초기화 로직이 중복 실행되지 않도록 플래그를 두는 처리가 필요할 수 있습니다. - 인자 불일치:
__new__와__init__은 동일한 인자를 전달받으므로 가변 인자(*args, **kwargs)를 활용해 유연하게 대처하는 것이 좋습니다.
6. 결론: 파이썬의 객체 철학 이해하기
파이썬에서 __new__는 '무(無)'에서 '유(有)'를 창조하는 조각가이며, __init__은 창조된 조각상에 옷을 입히고 이름을 붙이는 화가와 같습니다. 이 두 단계의 차이를 명확히 이해한다면, 단순히 클래스를 사용하는 수준을 넘어 파이썬 엔진이 객체를 다루는 방식을 제어할 수 있는 고수준의 프로그래밍이 가능해집니다.
글 내용의 출처 및 참고 문헌
- Python Software Foundation: The Python Language Reference - Data Model
- Fluent Python 2nd Edition (Luciano Ramalho): "Object References, Mutability, and Customizing Classes"
- Effective Python (Brett Slatkin): "Item 50: Use __set_name__ and __init_subclass__ for Class Metaprogramming"
- Stack Overflow: "Real-world use cases for __new__" (Community Discussion)
'Artificial Intelligence > 60. Python' 카테고리의 다른 글
| [PYTHON] 메모리 누수 해결하는 3가지 비결 : Weakref 모듈 활용 방법과 강한 참조와의 차이 (0) | 2026.03.03 |
|---|---|
| [PYTHON] 객체 복사의 2가지 메커니즘 : copy와 deepcopy의 내부 순회 방식 차이 해결 (0) | 2026.03.03 |
| [PYTHON] 메모리 효율을 극대화하는 제너레이터와 이터레이터의 3가지 핵심 프로토콜 차이와 활용 방법 (0) | 2026.03.02 |
| [PYTHON] yield from 구문이 재귀적 제너레이터 구조에서 해결하는 3가지 복잡성 문제와 최적화 방법 (0) | 2026.03.02 |
| [PYTHON] Protocol (PEP 544)을 이용한 구조적 타이핑 구현 방법과 명시적 상속의 3가지 차이점 해결 (0) | 2026.03.02 |