객체 지향 프로그래밍의 핵심 개념 정리

프로그래밍 패러다임: 절차지향과 객체지향

프로그래밍에는 두 가지 주요 접근 방식이 존재한다. 하나는 절차지향적 사고방식이고, 다른 하나는 객체지향적 사고방식이다.

절차지향 프로그래밍 문제 해결을 위한 단계를 나누어 각 단계별로 코드를 작성하는 방식이다. 이 방법은 대부분의 프로그램에서 기본적으로 사용되며, 규모에 따라 비중이 달라질 뿐이다.

객체지향 프로그래밍 데이터와 기능을 하나의 단위로 묶어 '객체'로 표현하고, 이 객체들이 어떻게 상호작용하는지를 중심으로 설계한다. 예를 들어 게임 개발 시 플레이어 캐릭터나 환경 자원은 모두 독립적인 객체로 모델링된다. 사용자의 입력에 따라 객체의 상태가 변화하며, 개발자는 이러한 객체들의 행동 규칙을 정의하는 데 집중한다.

객체지향과 절차지향은 서로 보완적이며, 실제 프로젝트에서는 혼합하여 사용된다. 문제의 성격에 따라 어느 방식이 더 적합한지는 다르다.

클래스와 인스턴스의 관계

클래스는 동일한 속성과 행동을 공유하는 객체들의 틀이다. 인스턴스는 클래스로부터 생성된 구체적인 객체이며, 클래스는 인스턴스의 설계도 역할을 한다.

class Vehicle:
    brand = "Unknown"
    
    def __init__(self, model):
        self.model = model
    
    def start_engine(self):
        return f"{self.model} 엔진 시작"

인스턴스 생성 및 속성 접근:

car1 = Vehicle("Tesla")
car2 = Vehicle("Hyundai")

print(car1.brand)  # Unknown
print(car1.model)  # Tesla

# 인스턴스만의 고유 속성 추가
car1.year = 2023
print(car1.__dict__)  # {'model': 'Tesla', 'year': 2023}
print(car2.__dict__)  # {'model': 'Hyundai'}

속성 변경과 동작 원리

인스턴스의 속성은 . 연산자로 직접 수정 가능하며, 이는 클래스 수준의 속성에는 영향을 주지 않는다.

car1.brand = "NewBrand"
print(car1.brand)  # NewBrand
print(Vehicle.brand)  # Unknown (클래스 속성은 그대로)

또한 인스턴스에 새로운 속성을 동적으로 추가할 수 있다.

car1.color = "Red"

초기화 메서드: __init__

인스턴스 생성 시 자동으로 호출되는 특수 메서드로, 인스턴스 고유의 초기값을 설정한다.

class Animal:
    species = "Unknown"
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
dog = Animal("Buddy", 5)
print(dog.name)  # Buddy
print(dog.age)   # 5

메서드의 종류: 바인딩 방식

인스턴스 메서드 (self)

클래스 내부의 메서드는 기본적으로 인스턴스에 바인딩되어 있으며, 첫 번째 인자로 self가 전달된다.

class Person:
    def __init__(self, name):
        self.name = name
    
    def greet(self):
        return f"안녕, 나는 {self.name}이야."

p1 = Person("Alice")
print(p1.greet())  # 안녕, 나는 Alice이야.

클래스 메서드 (@classmethod)

클래스 자체에 바인딩되는 메서드로, cls 매개변수를 통해 클래스 정보에 접근할 수 있다.

class Config:
    env = "production"
    
    @classmethod
    def get_env(cls):
        return cls.env

print(Config.get_env())  # production

정적 메서드 (@staticmethod)

바인딩되지 않은 일반 함수와 유사하며, 클래스나 인스턴스를 통하지 않고도 호출 가능하다.

class MathUtils:
    @staticmethod
    def add(a, b):
        return a + b

result = MathUtils.add(3, 4)
print(result)  # 7

상속과 이름 검색 순서

상속은 공통적인 속성과 기능을 부모 클래스에서 추출하여 자식 클래스가 재사용하는 방식이다.

class Parent:
    value = 100

class Child(Parent):
    pass

child = Child()
print(child.value)  # 100 (부모 클래스의 속성 접근)

다중 상속과 MRO

파이썬은 다중 상속을 지원하며, 이름 검색 순서는 mro() 메서드로 확인할 수 있다.

class A:
    x = "A"

class B(A):
    x = "B"

class C(A):
    x = "C"

class D(B, C):
    pass

print(D.mro())
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
  • 비마름모형: 왼쪽부터 깊이 우선 탐색
  • 마름모형: 교차점은 마지막에 처리되며, 지역적으로 넓이 우선 탐색처럼 작동

상속 확장: super() 활용

자식 클래스에서 부모 클래스의 메서드를 오버라이드하면서도 원래 기능을 유지하고 싶을 때 super()를 사용한다.

class Base:
    def method(self):
        return "Base called"

class Derived(Base):
    def method(self):
        result = super().method()  # 부모의 메서드 호출
        return f"{result} + Extended"
d = Derived()
print(d.method())  # Base called + Extended

이렇게 하면 기존 로직을 유지하면서도 확장이 가능해진다.

태그: python 객체지향 상속 메서드 클래스

6월 7일 17:51에 게시됨