머신러닝&딥러닝

객체 지향 프로그래밍 #1 클래스와 인스턴스

seungbeomdo 2023. 1. 15. 20:17

파이썬을 제대로 다룰 줄 아는 건지에 대한 의심이 들었다. 전처리, 기술 분석, 회귀 분석, 가설 검정, 시각화 이런 데이터 분석의 프로세스를 구현하는 능력은 있다고 생각했는데, 어쩐지 넘파이 판다스 이상의 단계로는 나아가지 못한다는 느낌이다. 사실 언급한 과정들이 넘파이 판다스만 할 줄 알면 되는 것들이긴 한데... 뭔가 아쉽다. 나한테 있어서 파이썬은 프로그래밍 툴이라기보다는 매우 크고 유연한 계산기일 뿐이다.

 

내가 컴공과도 아니고! 데이터 분석으로는 이 정도면 족하다! 라고 말하기에는 다른 사람들의 기술 수준이 점점 높아지고 있는 것 같고... 머신러닝 모델링을 해봤다고/해보고 싶다고 말할 실력이 되려면 좀더 깊은 프로그래밍의 세계로 들어가야겠다는 생각이다. 이 지점에서 늘 내 발을 잡던 것들은 '객체 지향 프로그래밍'이라는 큰 주제로 묶이는 인상이 있었다. 도대체 그게 뭔데? 솔직히 클래스가 아직까지도 왜 필요한 건지 모르겠는데 모델 코드 베끼려고 깃허브 들어가보면 클래스를 안 쓰는 사람이 없다. 뒤늦게나마 정석으로 파이썬에 입문해보려고 한다.


0. decorator

본론으로 들어가기 전에 자주 쓰이는 decorator가 무엇인지 정의하자.

  • 코드를 쓰다보면 복수의 함수들이 동일한 기능을 사용하도록 할 필요가 종종 발생한다.
  • 가령 반갑다고 인사하는 함수 hi()와 잘 가라고 인사하는 함수 bye()을 정의했다고 하자.
def hi():
  print('Hi!')

def bye():
  print('Bye!')

  • 그런데 함수의 결과를 출력할 때, 인사를 누가 했는지 알려주는 기능이 필요해졌다고 하자. 먼저 함수를 정의할 때 사람 이름을 출력하는 기능을 추가하는 방법을 떠올릴 수 있다.
  • 하지만 이 경우 사용하는 모든 함수들에 대해 일일이 기능을 추가해야 하는 번거로움이 있고,
  • 또 <사람 이름 출력하기>를 해야하는 함수도 있지만 어떨 때는 하면 안 되는 함수도 있다고 하자.
  • 그럴 경우 decorator의 사용이 좋은 대안이 된다.

 

  • decorator의 사용 방법은 아래와 같다. 먼저 임의의 함수 A를 인자로 받는 함수 B를 정의하고, B 함수는 A 함수의 결과를 출력함과 함께 원하는 부가적인 기능을 추가한 함수라고 하자. 가령, 
def who_said(func):

  def temp():
    print('I said')
    func()

  return temp
  • who_said 함수는 인자로 들어온 함수의 결과를 출력하기 앞서서 'I said'라는 문구를 출력해주는 함수이다. 이 함수를 decorator로 사용하면 함수를 정의할 때 유연하게 기능을 추가해줄 수 있다.
@who_said
def hi():
  print('Hi!')
  
@who_said
def bye():
  print('Bye!')
  • 함수를 실행하면 함수 내부에 'I said'를 출력하는 기능이 없음에도 불구하고 출력되는 것을 확인할 수 있다.


1. Class와 Instance

1.1. 클래스와 인스턴스

객체 지향 프로그래밍을 구현하는 중요한 구성요소인 클래스와 인스턴스에 대해서 알아보자.

  • 클래스(Class): 객체를 생성하는 설계도. 특히 객체 지향 프로그래밍(OOP)의 원칙을 준수하는 설계도를 말한다(OOP의 원칙은 다음 장들에서 다룬다).
  • 인스턴스(Instance): 인스턴스는 곧 객체를 말한다. 이 객체는 클래스에 의해서 생성된 객체이다.
    • 동일한 하나의 클래스를 통해 생성된 서로 다른 객체들은 서로에 대하여 독립적이다. 즉 한 인스턴스를 수정한다고 해서 다른 인스턴스가 수정되지 않는다.

1.2. 클래스 생성하기

클래스를 생성하는 방법을 알아보자.

  • 클래스는 기본적인 내용만 보자면 크게 세 가지로 구성된다. 생성자와 속성(변수), 그리고 메서드(행위)이다.
    • 생성자: 생성자 함수는 클래스를 생성하는 함수이다. 여기서 정의된 self 속성은 생성된 클래스에 의해 만들어진 인스턴스을 지칭하는 속성이다.
    • 속성(변수): 속성은 클래스(에 의해 만들어진 인스턴스) 내에서 사용되는 다양한 변수들을 말한다.
    • 메서드(행위): 메서드란 클래스(에 의해 만들어진 인스턴스)가 수행하는 행위이다.
  • 이상을 염두에 두고, 계산 기능을 수행하는 인스턴스들을 만들기 위해서 클래스를 설계해보자. 우리가 원하는 계산기는 사칙연산을 기본으로 수행할 수 있어야 한다.
class Cal: 
  
  def __init__(self, a, b): #생성자 함수; self는 이 클래스에 의해 만들어진 인스턴스를 지칭
    self.a = a #속성 a
    self.b = b #속성 b

  def add(self): #메서드 add
    return self.a + self.b

  def sub(self): #메서드 sub
    return self.a - self.b

  def mul(self): #메서드 mul
    return self.a * self.b

  def div(self): #메서드 div
    return self.a / self.b
  • 생성자는 __init__ 함수를 말한다. 이때 self 속성이 필수 인자로 들어와야 하고, 클래스의 여러 행위들을 위해서 필요한 속성들을 선택적으로 추가할 수 있다. 
  • 계산기이기 때문에, 계산에 사용할 두 숫자 a와 b를 속성으로 받아들인다. 이 속성을 인스턴스의 속성으로 받아들이기 위해서는 self.a = a와 같은 코드들이 필요하다. 인자 a를 self의 변수 공간에 집어넣어주겠다는 의미이다.
  • 계산기이기 때문에, 이 클래스로 만들어진 인스턴스의 메서드(행위)는 각각의 사칙연산이다.

1.3. 인스턴스 생성하기

정의된 클래스를 사용해 인스턴스를 생성하는 방법을 알아보자.

  • 인스턴스를 생성하는 것은 비교적 간단하다.
cal1 = Cal(1,2) #실행되는 순간, cal1은 self가 된다. 1은 a, 2는 b가 된다.

cal2 = Cal(3,4) #cal2와 독립적인 다른 인스턴스
  • 클래스를 생성할 때 사용했던 인자들을 알맞게 넣어주면, 하나의 고유한 인스턴스가 생성된다. 이 경우에 cal1과 cal2가 각각 인스턴스가 된다. 1과 2, 3과 4는 각각 cal1과 cal2의 속성이 된다.
  • 생성된 인스턴스의 속성으로 접근하는 방법은 아래와 같다.

  • 생성된 인스턴스의 메서드를 수행하는 방법은 아래와 같다.