Application/Python

[Python] 파이썬 생성자(__init__) 쉽게 이해하기

devsalix 2026. 5. 11. 08:30
728x90

파이썬 생성자(init) 쉽게 이해하기

지난번에 강아지 클래스 만들 때 set_info() 같은 메서드로 이름이랑 나이를 따로 넣었던 거 기억나세요? 클래스를 먼저 만들고, 그다음에 메서드를 한 번 더 호출해서 정보를 채워 넣는 방식이었잖아요.

d = Dog()
d.set_info("뽀삐", 3)

 

두 줄을 꼭 써야 하니까 살짝 답답하셨을 거예요. 저도 그랬거든요.

근데 사실 이걸 한 줄에 끝낼 수 있는 방법이 있어요. 바로 오늘 배울 생성자예요.


파이썬 생성자, 왜 필요할까요

생성자라는 단어부터 이미 어렵죠. 그냥 이렇게 생각하시면 돼요.

인스턴스가 태어나는 순간에 자동으로 실행되는 초기 세팅 코드.

회원가입을 떠올리시면 이해가 쉬워요. 사이트에 가입할 때 이름, 이메일, 나이를 한 번에 입력하잖아요. 가입 버튼을 누르면 그 정보로 내 계정이 만들어지고요. 가입 따로, 정보 입력 따로 안 하죠. 한 번에 끝납니다.

파이썬에서도 이걸 똑같이 할 수 있어요. 그게 __init__이라는 메서드예요.


python init이 하는 일

코드부터 보시죠.

class Dog:
    def __init__(self, name):  # 인스턴스가 만들어질 때 자동 실행
        self.name = name        # 받은 이름을 인스턴스에 저장

 

처음 보면 양쪽에 언더스코어가 두 개씩 붙어 있어서 좀 이상해 보이실 거예요. __init__ 이게 도대체 뭔가 싶죠. 그냥 파이썬이 약속해 둔 특별한 이름이라고 생각하시면 됩니다. 양쪽에 두 개씩 정확히 맞춰서 쓰셔야 해요. 한 개씩 쓰면 자동 호출이 안 돼요.

이제 인스턴스를 만들어 볼게요.

d = Dog("뽀삐")   # 괄호 안 값이 __init__으로 들어감
print(d.name)     # 뽀삐

 

Dog() 괄호 안에 "뽀삐"를 넣었더니 그게 그대로 인스턴스의 이름이 됐어요.

여기서 헷갈리시는 분 많은데, 우리가 __init__을 직접 부른 적이 한 번도 없거든요. 그냥 Dog("뽀삐")라고 썼을 뿐이에요. 클래스 이름에 괄호를 붙이는 행위 자체가 __init__ 호출이에요. 회원가입 버튼 한 번 누르면 가입 양식이 자동으로 처리되는 거랑 똑같아요.


self.name = name이 진짜 헷갈리는 이유

이 줄이 처음에 제일 어렵더라고요.

self.name = name

 

이름이 양쪽 다 똑같아서 "뭐가 뭐지?" 싶잖아요. 일부러 다르게 써보면 의미가 명확해져요.

def __init__(self, n):
    self.name = n   # 오른쪽 n: 잠깐 받은 값 / 왼쪽 self.name: 인스턴스에 영구 저장

 

오른쪽 n__init__이 잠깐 들고 있는 매개변수예요. 함수가 끝나면 사라지죠. 왼쪽 self.name은 이 인스턴스에 영구적으로 붙여둘 속성이고요. 받은 값을 인스턴스의 짐칸에 넣어두는 작업이라고 보시면 돼요.

관례상 같은 이름을 많이 쓰는데, 그래서 더 헷갈리는 거예요. 익숙해지면 자연스러워집니다.


파이썬 인스턴스 여러 개 만들어보기

매개변수를 여러 개 받게 해볼게요.

class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def bark(self):
        print(f"{self.name}({self.age}살): 멍멍!")

d1 = Dog("뽀삐", 3)
d2 = Dog("초코", 5)
d3 = Dog("바둑이", 7)

d1.bark()   # 뽀삐(3살): 멍멍!
d2.bark()   # 초코(5살): 멍멍!

 

같은 Dog 클래스에서 만들었는데 셋 다 정보가 다르죠. 클래스가 붕어빵 틀이고, 인스턴스가 거기서 찍어낸 붕어빵이에요. 틀은 하나지만 안에 든 팥, 슈크림, 초코는 다를 수 있는 거고요.


기본값을 미리 정해두기

매번 모든 값을 넣기 귀찮을 때는 기본값을 줄 수 있어요.

class Dog:
    def __init__(self, name="이름없음", age=0):
        self.name = name
        self.age = age

d1 = Dog()              # 이름없음, 0
d2 = Dog("뽀삐")         # 뽀삐, 0
d3 = Dog("초코", 5)      # 초코, 5

 

인자를 안 넘겨도 기본값이 들어가서 에러가 안 나요. 이거 의외로 자주 씁니다.


python init에서 자주 만나는 에러

가장 흔한 게 이 에러예요.

class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

d = Dog("뽀삐")
# TypeError: __init__() missing 1 required positional argument: 'age'

 

age를 안 넣어서 난 에러예요. "필수 인자가 하나 빠졌어요"라는 뜻이거든요. __init__에 적어둔 매개변수 개수만큼 모두 넣어주셔야 해요.

그리고 가끔 __init__에서 return으로 뭘 돌려주려고 하시는 분이 있는데, 그러면 안 돼요. 생성자는 초기 세팅만 하는 거지 값을 반환하는 게 아니거든요.


실용 예제: BankAccount 클래스 만들기

조금 실전스러운 예제로 마무리할게요.

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner       # 예금주
        self.balance = balance   # 잔액 (기본 0원)

    def deposit(self, amount):
        self.balance += amount
        print(f"{amount}원 입금. 잔액: {self.balance}원")

    def withdraw(self, amount):
        if amount > self.balance:
            print("잔액 부족")
            return
        self.balance -= amount
        print(f"{amount}원 출금. 잔액: {self.balance}원")

acc = BankAccount("홍길동", 10000)
acc.deposit(5000)    # 5000원 입금. 잔액: 15000원
acc.withdraw(3000)   # 3000원 출금. 잔액: 12000원
acc.withdraw(20000)  # 잔액 부족

 

계좌를 만드는 그 순간에 예금주와 시작 잔액이 같이 세팅되죠. 한 번 만들어두면 그 계좌만의 잔액이 계속 따라다니고요.

여러분도 한번 해보세요. 위 코드에 transfer(other_account, amount) 메서드를 추가해서 한 계좌에서 다른 계좌로 돈을 옮기는 기능을 만들어 보시면 좋아요. 막히시면 댓글로 남겨주세요.

근데 막상 이렇게 만들다 보면 또 고민이 생겨요. 강아지 클래스 다음에 고양이 클래스, 햄스터 클래스도 만들어야 하면 어떨까요? 매번 이름이랑 나이 받는 코드를 똑같이 또 쓰는 건 좀 비효율적이잖아요.

공통된 부분을 한 번만 쓰고, 나머지를 가져다 쓰는 방법이 있는데요. 그게 다음에 다룰 상속이에요.


 


제 글이 도움이 되셨다면 댓글 & 공감 부탁드려요 😀

 

 
728x90