본문 바로가기
Python

파이썬(Python): 클래스(class) 안 def __init__(self): 와 self 등을 제대로 이해하기

by WritingStudio 2022. 8. 16.
반응형

"def __init__(self):"
 
파이썬python을 약간이라도 다루기 시작한 사람이라면 이내 마주치는 구문이다. 개인적으로는 def __init__(self) 구문은 파이썬에서만 사용하는 함수로 안다. 다른 언어에서 본 적이 없기에(그리고 다른 언어는 다뤄본 적이 없기에) 더 당황스럽기도 하다.
 
일단 의미부터 설명하자면 __init__은 initialize를 표현한 구문이다. initialize는 '기본값 설정하기'라는 뜻에 가깝다(대개  __init__을 '초기화' 라고 설명하는데 한국 IT어 용례상 '기본값 설정하기'로 이해하는 편이 낫다).
 
이제부터 시작되는 예시 코드 및 해설을 따라가면 __init__의 역할은 물론 self란 무엇인지, 그리고 클래스class를 왜 쓰는지도 이해하게 될 것이다.

Calc 클래스(class) 만들기

Calc라는 클래스(class)를 만들어보자. Calc는 그 뜻 그대로 사칙연산인 덧셈, 뺄셈, 곱셈, 나눗셈을 해 준다.
 
Calc 클래스(class)는 아래와 같이 간단하게 작성된다.

class Calc:
    def __init__(self, a, b):
        self.x = a
        self.y = b

    def plus(self):
        return self.x + self.y

    def minus(self):
        return self.x - self.y

    def multiply(self):
        return self.x * self.y

    def divide(self):
        return self.x / self.y

 

self는 뭘까

우선 self가 무엇인지 알아보기 위해 'self.x = a'에 정지점을 설정하고 디버깅을 해보도록 하자.
 
디버깅 창에 'self'라고 치면 다음과 같은 문구가 뜬다.

self의 정체

여기서 __main__은 당신이 지금 작성 중인 python 파일을 말한다. __main__.Calc는 작성중인 파이썬 코드상의 Calc 클래스를 뜻한다. 그렇다. self는 Calc 클래스 그 자체이다.
 
self를 다른 단어로 바꾸어 써도 아무런 문제가 없다. 그저 self라고 쓰는 편이 의미상 편하기에 그렇게 쓰는 것이다. 즉 위 코드를 아래와 같이 self를 안 쓰고 작성해도 아무 문제가 없다.

class Calc:
    def __init__(Calc, a, b):
        Calc.x = a
        Calc.y = b

    def plus(Calc):
        return Calc.x + Calc.y

    def minus(Calc):
        return Calc.x - Calc.y

    def multiply(Calc):
        return Calc.x * Calc.y

    def divide(Calc):
        return Calc.x / Calc.y

Calc가 아닌 aaa, bbb 등 어떤 문자열을 써도 상관 없다.
어떻게 쓰든 __init__에서 첫 번째로 들어가는 변수명은 Calc 클래스 스스로를 지칭하게 된다.
이는 파이썬 내에서 정해진 매우 중요한 규칙이다.

__init__ 이해하기

다시 원래 코드로 돌아와 보자.

class Calc:
    def __init__(self, a, b):
        self.x = a
        self.y = b

    def plus(self):
        return self.x + self.y

    def minus(self):
        return self.x - self.y

    def multiply(self):
        return self.x * self.y

    def divide(self):
        return self.x / self.y

위 코드에서 def __init__ 부분을 따로 떼어서 보자.

class Calc:
    def __init__(self, a, b):
        self.x = a
        self.y = b

self는 Calc 클래스 스스로라고 앞서 설명했다. 따라서 __init__ 함수는 외부 변수 로는 a와 b 라는 두 값을 받는다. 사칙연산 클래스이니 a와 b는 모두 숫자여야 한다.
 
그렇다면 self.x = a는 무슨 뜻일까. self가 클래스 스스로이니 self.x는 Calc 클래스 내에서 x가 갖는 값이다. 즉, self.x = a는 입력받은 외부 변수 a를 Calc 클래스 내의 x의 값으로 정하는 명령어이다(보통 편의상 self.a = a 식으로 많이 쓰지만 본 글에서는 설명 편의상 self.x = a 식으로 썼다). self.y = b도 같은 뜻이다.
 
그럼 그냥 def __init__(a, b)라고 하면 될 걸 왜 굳이 앞에 귀찮게 self와 같은 변수를 의무적으로 입력하게 했는가 하는 의문이 생긴다. 이에 대해서는 위 코드 전체를 다룬 후에 마지막에 이야기하도록 한다.

Calc 클래스를 사용하여 객체(object)인 인스턴스(instance) 생성하기

Calc 클래스는 위에서 정의하듯 본인 스스로에 추가하여 a, b 두 변수를 받도록 되어 있다. 그러면 이제 Calc 클래스에 숫자 두 개를 입력하기로 하자.

i = Calc(2,3)

위 명령을 이해하는 것이 생각보다 매우 중요하다.
 
Calc(2,3)은 Calc 클래스에 숫자 2와 3을 입력하라는 코드이다. 즉, Calc(2,3)은 Calc 클래스에 숫자 2와 3이 입력된 상태인 무언가이다. 그리고 우리는 그 무언가를 객체(object)라고 부른다.
 
파이썬 명령창에  Calc(2,3)을 실행해보자.

object 이다.

 
그러므로 i = Calc(2,3)은 Calc 클래스에 2와 3이 입력된 상태인 이 객체를 i라고 지정하겠다는 명령어이다. 그러니 i도 물론 객체(object)이다.

i도 객체(object)

그리고 이 객체 i는 Calc 클래스에 의해 만들어진 객체이다. 이 경우 우리는 객체 i를 Calc의 인스턴스(instance)라고 한다. 이 역시도 파이썬에 물어보면 쉽게 알 수 있다.

객체(object) i는 Calc 클래스의 인스턴스(instance)입니까? 답: 그렇다.

Calc 클래스에 의해 생성된 객체(object)인 'i' 인스턴스(instance) 활용하기

자, 이렇게 해서 i라는 Calc 클래스에 2와 3이 입력된 상태인 객체이자 Calc 클래스의 인스턴스(instance)를 만들었다.
 
Calc(2,3)을 실행하면 본 글에서 예시로 든 코드상에서는 self.x = 2, self.y = 3 이 된다.
 
이제 이를 활용해보자.

2와 3의 사칙연산

i 자체가 Calc 클래스에 2와 3이 입력된 상태인 객체(object)이기 때문에 Calc가 가진 함수들을 실행만 시킴으로써 사칙연산을 할 수 있다.
 
이 때 plus, minus, multiply, divide 등 Calc를 이루는 함수(function)들을 메소드(method)라고 한다. 즉, 클래스를 생성하는 이유는 메소드(method)를 활용하기 위함이다.

다시 __init__과 self로 돌아와서

자, 원 코드를 다시 한 번 보자.

class Calc:
    def __init__(self, a, b):
        self.x = a
        self.y = b

    def plus(self):
        return self.x + self.y

    def minus(self):
        return self.x - self.y

    def multiply(self):
        return self.x * self.y

    def divide(self):
        return self.x / self.y

앞서 말했듯  __init__은 파이썬 내에서의 약속이다. 그리고 __init__은 첫 번째 변수로는 보통 self로 표시되는 해당 클래스 스스로를 받도록 되어있다고 말했다. self는 왜 필요한걸까?
 
쉽게 말해 self가 필요한 이유는 __init__이 받는 실질적인 주요 변수인 a, b를 클래스(class) 전체가 사용할 수 있도록 만들기 위해서다. __init__함수가 self(본 글에서는 Calc 클래스)를 받지 않는다면 __init__ 함수 안에서 Calc 클래스를 불러올 방법이 없어진다. 그래서 파이썬에서는 __init__ 첫째 변수가 클래스 스스로를 받도록 함으로써 self.x = a와 같은 명령어가 가능토록 한 것이다.
 
만약 __init__(self, a, b)라고 쓰지 않고 __init__(a, b)라고만 쓰게 만들었다면 받은 변수 a,b를 Calc 클래스 전체에서 쓸 수 있도록 저장을 하는 작업이 불가능해진다. 즉, __init__(a,b)라고만 해버리면 그냥 __init__함수 안에서만 a, b를 쓸 수 있지 plus, minus 등과 같은 다른 메소드(method) 함수들과는 변수 공유가 불가능해진다.
 
그렇기에 파이썬에서는 __init__ 함수가 첫 번재 변수로는 무조건 해당 클래스 스스로를 받도록 설정한 것이다. 그리고 plus와  minus같은 함수이자 메소드들도 plus(self), minus(self) 식으로 Calc(=self) 클래스 자체를 변수로 입력 받고 Calc 클래스 안에서 지정된 변수들을 self.x, self.y식으로 불러다 쓰게 만들었다.

마치며

__init__함수와 self는 처음 보면 '뭐하러 이런 식으로 하지?' 싶다. 하지만 사용하고 이해하다 보면 상당히 귀찮아 질 수도 있는 작업을 __init__과 self로 인해 아주 손쉽고 효율적으로 처리할수 있구나 하는 생각을 하게 된다. 처음에는 직관적이지 않지만 이해할수록 매우 직관적이기도 하다.
 
 

반응형

댓글