이번 시간에는 객체 지향 프로그래밍(Object Oriented Programming, OOP)에 대해서 배웁니다.

1. 객체지향 프로그래밍이란?

객체지향 프로그래밍이란, 실제 세계에 존재하는 개체(entity), 또는 개념(concept)을 추상화(abstraction)해서 코드로 나타낸 객체(object)을 중심으로 프로그램을 개발하는 패러다임을 말합니다.

왜 객체지향을 사용할까요?

OOP는 프로그램 변경이 유연하게 이루어질 수 있는 구조로 작성되도록 하는 패러다임(Paradigm)입니다. 기존의 프로그래밍은 코드의 실행 순서를 가지고 프로그램을 설계했다면, OOP에서는 각 프로그래밍 요소들을 하나의 객체로 보고, 각자의 역할과 기능을 기반으로 프로그램을 설계합니다.

이렇게 하면 각 객체 간의 독립성이 강해지는 장점이 있고, 객체가 실제 세계의 어떤 개체(Entity)를 추상화(Abstraction)해 나타내기 때문에 실제 세계의 문제를 해결하는 데 더 편리한 장점이 있습니다.

객체지향을 사용하는 이유는 추상화된 코드를 사용해 클래스의 의미와 역할을 쉽게 이해하기 위해서입니다. 클래스를 사용하면 코드의 재사용성이 높아지고, 각 역할별로 객체가 나누어지기 때문에 유지보수가 쉬워지는 장점도 있습니다.

<aside> 💡 객체지향의 개념과 정의에 대해서 더 자세히 알고 싶으시다면 아래 링크를 참조하세요.

</aside>

객체지향 프로그래밍이란? 5분 정리(OOP, Object Orientied Programming)

클래스와 객체

지금까지는 코드를 작성하면서 코드 블럭, 그리고 함수라는 단위를 생각하면서 작성했습니다. 그런데 이제부터는 객체라는 관점에서 코드를 작성할 것입니다. 파이썬에서 객체는 클래스를 사용해 정의합니다. 클래스란, 어떤 객체를 나타내기 위한 틀과 같습니다.

예를 들어, 붕어빵 기계에서는 똑같은 모양의 붕어빵이 계속 만들어집니다. 하지만 붕어빵 기계의 빵틀 자체는 변하지 않습니다. 그리고 여러 개의 붕어빵은 실제 모양이나 맛은 다르지만 전체적으로 붕어빵이라는 공통점을 지니고 있습니다. 그래서 이 붕어빵들은 하나의 붕어빵 기계에서 나온 것이라는 걸 알 수 있습니다.

붕어빵 기계에서 나온 붕어빵처럼, 클래스는 자기 자신에 정의된 클래스의 구성 요소를 가지는 새로운 객체를 만들어내는데, 이를 인스턴스라고 합니다. 이처럼 클래스에서 객체 또는 인스턴스를 생성하는 것을 객체화(Instantiation)라고 부릅니다.

붕어빵 기계(클래스) → 붕어빵(인스턴스)

클래스를 한번만 정의해 놓으면 같은 속성을 공유하는 인스턴스들을 계속 만들어낼 수 있기 때문에 코드의 길이가 짧아지고, 클래스의 정의가 바뀌면 나머지 인스턴스들의 속성도 모두 변하기 때문에 유지보수 측면에서도 편리한 장점이 있습니다.

<aside> 💡 [객체와 인스턴스의 차이]

클래스로 만든 객체를 인스턴스라고도 한다. 그렇다면 객체와 인스턴스의 차이는 무엇일까? 이렇게 생각해 보자. cookie = Cookie() 이렇게 만든 cookie는 객체이다. 그리고 cookie 객체는 Cookie의 인스턴스이다. 즉 인스턴스라는 말은 특정 객체 cookie 가 어떤 클래스 Cookie 의 객체인지를 관계 위주로 설명할 때 사용한다. "cookie는 인스턴스"보다는 "cookie는 객체"라는 표현이 어울리며 "cookie는 Cookie의 객체"보다는 "cookie는 Cookie의 인스턴스"라는 표현이 훨씬 잘 어울린다.

</aside>

사람을 추상화해봅시다

이번에는 사람을 추상화해서 클래스를 설계해 보겠습니다. 이 객체를 만들기 위한 설계도를 클래스(class)라고 하며, 클래스로부터 만들어진 객체는 프로퍼티(property)과 메소드(method)를 가지고 있습니다.

정리하자면 프로퍼티는 객체에 속한 변수, 메소드는 객체에 속한 함수를 의미합니다.

2. 파이썬에서 클래스 정의하기

파이썬의 작명 규칙(Naming convention)

지금까지 변수와 함수의 이름을 스네이크 케이스로 지었습니다. 파이썬에서 유일하게 다른 이름 규칙을 따르는 것이 바로 클래스입니다. 클래스 이름은 반드시 파스칼 케이스로 지어야 합니다.

# 1 : snake case
twosome_place

# 2 : Pascal case
TwosomePlace

클래스 정의하기

파이썬에서 클래스는 다음과 같이 정의합니다.

class ClassName:
    def method1(self, param1, param2...):
        ...

    def method2(self, param1):
        self.property1 = param1
        self.property2 = "Hello"

파스칼 케이스로 클래스 이름을 선언하고, 하위에 클래스에 속한 메소드들을 작성하면 됩니다. 또한 클래스는 프로퍼티를 가질 수 있다고 말했는데, 여기서 self.property1 이 클래스의 속성이며, 이 값을 method2 메소드의 파라미터로부터 받은 값으로 초기화하고 있습니다.

생성자와 소멸자

파이썬 클래스의 대표적인 메소드 두 가지인 생성자와 소멸자에 대해서 배워보겠습니다. __init__ 메소드를 생성자(constructor)라고 부르며, 생성자는 객체가 생성될 때 자동으로 호출됩니다.

이와 비슷하게 객체가 사라질 때 호출되는 메소드를 소멸자(destructor)라고 부릅니다. 소멸자는 __del__ 로 약속되어 있고 객체가 삭제되면 자동으로 호출됩니다.

class PoliteRobot:
    def __init__(self):
        print("안녕하십니까?") # 1

    def __del__(self):
        print("안녕히 계세요") # 3

robot = PoliteRobot()
print("안녕? 만나서 반가웠고 잘가!") # 2
del robot

위 예제 코드에서 robot 객체가 생성될 때 생성자가 호출되고, del 을 통해 객체가 삭제될 때 소멸자가 호출되는 것을 볼 수 있습니다.

클래스 설계에서 소멸자가 필요한 이유는 클래스로부터 객체화된 인스턴스가 어떤 특정 파일의 핸들 또는 동적 메모리를 점유하고 있는 경우, 동일 클래스로부터 만들어진 객체가 해당 파일 또는 메모리에 접근해 오류를 발생하지 않게끔 하기 위해서입니다.

생성자와 소멸자는 특별한 역할 때문에 다음과 같은 규칙을 가지고 있습니다.