본문 바로가기
Study/Lecture

[Python] 클래스(class)

by ngool 2024. 6. 27.

본 포스트에서는 파이썬에서 '클래스'라는 개념을 이해하기 쉽게 설명해볼 것입니다.

 

클래스는 제가 느낄 때 파이썬을 배움에 있어 가장 어려운 부분인 것 같습니다.

그렇기 때문에 이러한 개념은 우리가 쉽게 이해할 수 있는 주변 사물에 대한 비유를 들어서 '직관'을 잡는 것이 중요합니다.


클래스에 대한 직관적 이해

로봇에 한번 비유를 해보겠습니다.

로봇은 각각 자신이 어떻게 구성되어 있는지 상세히 기록되어 있는 설계도가 존재합니다.

그리고 각 로봇은 한가지 이상의 기능을 갖고 있죠.

 

이 때, 우리는 클래스에 대해 아래처럼 비유해볼 수 있습니다.

  • 클래스: 로봇 설계도
  • 메서드: 로봇이 가진 기능
  • 객체(인스턴스): 로봇
즉, 우리는 설계도(클래스)를 사용하면 같은 기능(메서드)을 가진 로봇(객체)을 계속 찍어낼 수 있다는 것입니다.

계산기 로봇 클래스 만들기

위 직관을 가지고 코드를 한번 작성해보도록 하겠습니다.

저는 값을 받고, 더하는 기능(메서드)를 가진 계산기 로봇 설계도(클래스)를 만들고, 그 설계도에 따라 로봇(객체) 두 개를 만들어 볼 것입니다.

 

먼저 설계도를 만들어 봅시다.

class CalRobot:
    def setdata(self, first, second):
        self.first = first
        self.second = second
    def add(self):
        return self.first + self.second

 

CalRobot이라는 설계도를 만들었습니다.

setdata, add라는 기능을 갖고 있네요!

 

그런데 특이한 점이 있습니다.

우리가 기존에 알던 함수와 살짝 다른점이 있는데요, 바로 'self'라는 친구가 존재한다는 겁니다.

 

self나중에 만들 객체를 받아주는 파라미터라고 생각하면 됩니다!

first, second는 우리가 아는 일반 파라미터입니다.

 

그렇다면 setdata 메서는 어떤 기능을 하는 걸까요?

바로, first와 second라는 두 숫자를 받은 뒤, self라는 독립적인 객체가 가진 고유한 속성으로 할당해주는 역할을 합니다.

쉽게 말해, 아래의 과정을 거칩니다.

  1. first, second 값을 받는다.
  2. self.first라는 self의 고유 속성에 first 값을 넣어준다.
  3. self.second라는 self의 고유 속성에 second 값을 넣어준다.

즉, setdata 메서드를 불러 두 숫자를 넣어준 이후에는 self라는 파라미터 하나만으로도 first와 second를 사용할 수 있게 되는 것이죠.

 

아래 add 메서드를 보면 파라미터가 self 밖에 없죠?

이미 setdata 메서드를 통해 self의 고유 속성으로 first, second를 받았기 때문에 self만 불러도 저렇게 first, second 값을 사용할 수 있는 것입니다!

 

 

자 그럼 설계도가 완성되었으니 이제 이 설계도를 바탕으로 로봇 두 개를 만들어보겠습니다.

a = CalRobot() # a라는 객체 생성
b = CalRobot() # b라는 객체 생성

 

a 로봇과 b 로봇을 만들어보았습니다.

이 두 로봇은 각자 독립적인 객체이므로, 서로 영향을 주지 않을 것입니다.

 

a.setdata(6,4) # a에 속성 추가
b.setdata(1,3) # a에 속성 추가

 

a 로봇과 b 로봇 각가에 다른 속성값을 넣어주겠습니다.

설계도에 있던 setdata 메서드를 사용하면 내부에서 두 숫자를 받아 self의 고유 속성으로 들어가게 되겠죠?

 

print(a.first)  # a의 첫번째 속성 출력
print(b.first)  # b의 첫번째 속성 출력

 

그럼 이제 각자 다른 속성값들이 잘 들어갔는지 확인해봅시다.

정말 a, b가 독립적인 객체라면 a.first와 b.first는 각각 6과 1이 나와줘야 할 겁니다.

6과 1이 나온 것을 확인할 수 있습니다.

이 결과는 a 로봇과 b 로봇에 각각 다른 숫자를 고유 속성으로 넣을 수 있다는 것을 의미합니다.

 

각자 다른 속성을 들고 있음을 확인했으니, add 메서드 결과는 뻔하겠죠?

print(a.add())  # a의 add 메서드 결과 출력 (6+4)
print(b.add())  # a의 add 메서드 결과 출력 (1+3)

결과는 너무나 당연하게도 a 로봇은 6+4=10을, b 로봇은 1+3=4를 잘 연산했음을 확인할 수 있습니다.


문제의 지점

위에서 만든 설계도는 사실 좋은 설계도가 아닙니다.

왜 그럴까요?

setdata 메서드를 우선적으로 실행하지 않으면 그 외 기능을 사용할 수 없게 설계되어 있기 때문입니다.

 

이게 무슨 말이냐 하면,

예를들어 아래 코드처럼 setdata 메서드를 사용하지 않고 add 메서드를 썼다고 해봅시다.

a = CalRobot()
a.add()

 

뭔가 문제가 있어보이죠?

맞습니다. setdata를 통해 속성을 주지 않은 채로 add를 실행해버렸습니다.

에러 발생

에러가 발생했습니다.

왜 이런 에러가 발생했을까요?

에러 위치

알다시피, add 메서드는 self라는 파라미터 하나만 받았습니다.

self가 first와 second라는 속성을 다 갖고 있다는 전제 하에 저렇게 코드를 작성한 건데요,

지금은 first와 second를 받은 적이 없고,

당연히 self.first, self.second에 아무 것도 할당이 되지 않았으니 속성 자체가 존재하지 않는 상태인 것이죠.

즉, 존재하지 않는 값을 반환하라고 했으니 에러가 난 것이라고 볼 수 있습니다.

더 사용하기 편리한 클래스 만들기

그렇다면 어떻게 해야 위 문제를 해결하고 더 편리한 설계도를 만들 수 있을까요?

바로, 생성자(constructor)를 사용하면 됩니다.

생성자란, 클래스 실행 시 가장 빠르게 1등으로 실행되는 메서드를 의미합니다.

클래스 내 메서드 명으로 __init__을 사용하면 그 메서드는 생성자가 됩니다.

 

어떻게 사용하는지, 바로 알아보도록 하겠습니다.

class CalRobot:
    def __init__(self, first, second):
        self.first = first
        self.second = second
    def add(self):
        return self.first + self.second

 

앞전의 설계도와 달라진 것은 setdata__init__으로 바뀐 것 하나 밖에 없습니다.

그러나 이 변화는 효율성 측면에서 큰 차이를 불러 일으킵니다.

 

어떤 차이가 있는지 보기 위해, 객체를 한번 만들어보겠습니다.

a = CalRobot()

에러 발생

객체를 만듦과 동시에 에러가 발생했습니다.

이건 first와 second를 입력하지 않았기 때문에 에러가 난 것인데요, 

__init__은 객체 생성과 동시에 즉시 실행되기 때문에, 객체 생성과 동시에 first, second 속성 입력을 강제하게 됩니다.

a = CalRobot(1, 2)  # 객체 생성과 동시에 first, second 속성 할당

 

이렇게 하니 에러가 나지 않습니다.

즉, __init__에 self 외에 다른 파라미터가 존재한다면, 객체 생성과 동시에 반드시 해당 파라미터 값을 객체 안에 속성으로 넣어줘야 합니다.

 

이제 더욱 편리해진 설계도를 바탕으로 계산기 로봇을 만들어 add 기능을 실험해보겠습니다.

class CalRobot:
    def __init__(self, first, second):
        self.first = first
        self.second = second
    def add(self):
        return self.first + self.second
        
a = CalRobot(1, 2)
print(a.add())  # 1+2

 

이처럼 setdata 메서드를 따로 호출하지 않고 단번에 add를 사용할 수 있게 되었습니다.