2026. 5. 17. 00:24ㆍAI/Python
객체 지향 프로그래밍 (OOP)의 4대 패러다임에는 캡슐화, 상속, 다형성, 추상화가 있다.
캡슐화는 데이터(속성)과 기능(메서드)를 하나로 묶고, 외부에서 직접 접근을 제한하여, 객체를 보호하는 개념이다.
상속은 기존 클래스의 속성과 메서드를 물려받아, 재사용하고 확장하는 구조를 가진다.
다형성은 같은 이름의 메소드라도, 객체의 종류에 따라 다르게 동작할 수 있게 하는 특징이다. (코드 유연성 up)
추상화는 복잡한 내부 구현은 숨기고, 핵심적인 기능만 외부에 제공하는 것으로, 사용자는 내부 구조를 몰라도
객체를 쉽게 사용할 수 있다는 개념이다.
이 4가지 개념을 통해, 코드의 재사용성, 확장성, 유지보수성을 크게 확장시킬 수 있다.
캡슐화
객체 지향 프로그래밍에서 데이터(속성)와 이를 처리하는 메소드를 하나로 묶고,
외부에서 내부 구현에 직접 접근하지 못하도록 제한하여 객체를 보호하는 개념이다.
Python에서는 public, _protected, __private와 같은 네이밍 규칙을 통해 접근 수준을 구분하며
필요할 경우 getter / setter 메소드나, @property 데코레이터를 이용해 안전하게 값을 읽고 수정할 수 있다.
이를 통해 객체를 임의로 변경하는 것을 방지하고, 코드의 안정성과 유지보수성이 향상된다.
class Fruit:
def __init__(self, name, price):
self.name = name # public
self.__price = price # private
@property
# getter
def get_price(self):
return self.__price
@property
# setter
def set_price(self.price);
self.price = price
fruit = Fruit("과일", 1000)
print(fruit.name) # 접근 가능
print(fruit.price) # 접근 불가
# @property는 getter/setter를 함수가 아닌 속성처럼 사용하게 해주는 캡슐화 방식
상속
객체 지향 프로그래밍에서 기존 클래스 (부모 클래스)의 속성과 메소드를 새로운 클래스 (자식 클래스)가 물려받아
재사용하고 확장하는 개념으로써, 공통 기능을 중복 작성하지 않고 코드 재사용성을 높일 수 있으며
자식 클래스는 부모 클래스의 기능을 그대로 사용하거나 필요한 부분만 추가하거나
오버라이딩 (재정의) 하여 동작을 변경할 수 있다.
Python에서는 class 자식 클래스 (부모 클래스) 형태로 상속을 구현하며
super()를 통해 부모 클래스의 초기화나 메서드를 호출할 수 있다.
이러한 구조는 코드의 유지보수성과 확장성을 크게 향상시키는 핵심 개념이다.
class ParentClass:
.......
class ChildClass(ParentClass):
........
상속 구조
자식 클래스의 생성자 메소드가 없으면 부모 클래스의 생성자를 따른다.
자식 클래스에 __init__ 생성자가 있으면 부모 클래스의 생성자 호출 안됨 (단, super() 생성자를 이용할 경우 부모 생성자 호출 됨)
super() 클래스는 현재 클래스의 부모 클래스를 참조하며, 부모 클래스의 생성자를 호출할 수 있다.
class Fruit:
def __init__(self, name, quantity):
self.name = name
self.quantity = quantity
def store(self, place):
print(f"{self.name}을 {place}에 보관합니다.")
def sell(self, amount):
print(f"{self.name}을 {amount}개 판매합니다.")
class Apple(Fruit):
# 부모 생성자 참조하여 호출할 경우
# 만약에 __init__ 생성자 메소드 없으면, 부모의 생성자 메소드 호출됨
def __init__(self, name, quantity):
super().__init__(name, quantity)
apple = Apple("사과", 20)
apple.store("냉장고") # 사과를 냉장고에 보관합니다
apple.sell(14) # 사과를 14개 판매합니다.
오버라이딩
상속 관계에서 부모 클래스에 이미 정의된 메소드를 자식 클래스에서 동일한 이름으로 다시 정의하여
동작을 변경하는 것을 의미한다. 이를 통해 자식 클래스는 부모의 기능을 그대로 사용할 수도 있고,
필요에 따라 일부 또는 전체 동작을 자신에 맞게 수정할 수도 있다.
Python에서는 별도의 키워드 없이 같은 메소드 이름을 정의하면, 자동으로 오버라이딩이 이루어지며
super()를 이용해 부모의 메소드를 같이 호출할 수도 있다.
class Fruit:
def __init__(self, name, quantity):
self.name = name
self.quantity = quantity
def store(self, place):
print(f"{self.name}을 {place}에 보관합니다.")
def sell(self, amount):
print(f"{self.name}을 {amount}개 판매합니다.")
class Apple(Fruit):
def wash(self):
print(f"{self.name}을 깨끗이 씻습니다.")
# 오버라이딩
def store(self, place):
print(f"{self.name}을 {place}에 강력히 보관합니다.")
다중 상속
다중 상속은 클래스가 둘 이상의 부모 클래스로부터 상속을 받는 기능을 의미한다.
Python은 다른 객체 지향 언어와 달리 다중 상속을 지원하는데, 사용할 경우 복잡성이 높아질 수 있어 주의해야 한다.
class Fruit:
def __init__(self, name, quantity):
self.name = name
self.quantity = quantity
def eat(self):
print(f"{self.name}을 먹습니다")
def sleep(self, hour):
print(f"{self.name}을 {hour} 시간 동안 보관합니다")
class Storage:
def __init__(self, name, quantity):
self.name = name
self.quantity = quantity
def process(self, hour):
print(f"{self.name}을 {hour} 시간 동안 가공합니다")
def sleep(self, hour):
print(f"{self.name}을 {hour} 시간 동안 저온숙성합니다")
# 다중 상속
class ProcessedFruit(Fruit, Storage):
pass
fruit = ProcessedFruit("사과", 10)
fruit.eat() # Fruit에 있는 eat() 메소드 실행
fruit.process(2) # Storage에 있는 process() 메소드 실행
fruit.sleep(8) # 문제 발생) 부모 2개가 같은 메소드가 있어서 충돌 우려 => MRO 알고리즘으로 결정
# => Fruit 부모의 메소드가 실행
print(ProcessedFruit.mro()) # mro 알고리즘에 따른 우선순위 순서
# ProcessedFruit > Fruit > Storage > Object
Object 클래스
모든 클래스의 최상위 부모 클래스 (루트 클래스)로써 사용자가 클래스를 정의할 때 명시적으로 상속하지 않아도
자동으로 상속되는 기본 클래스이다. 이 클래스는 객체가 가져야할 최소한의 공통 기능을 제공하며
__ str__, __repr__, __eq__와 같은 기본 매직 메서드의 기본 구현을 포함하고 있다.
따라서 모든 파이썬 객체는 내부적으로 Object를 기반으로 동작하며,
새로운 클래스를 정의할 때도 기본 기능을 물려받아 사용할 수 있다. 즉, 가장 기초가 되는 공통 부모라고 할 수 있다.
MRO (Method Resolution Order)
Python에서 다중 상속을 사용할 때 메소드나 속성을 찾는 순서를 정의하는 규칙이다.
MRO는 특히 여러 부모 클래스를 상속받는 경우에 어떤 부모 클래스에서 메서드를 먼저 찾을지 결정하며
이를 통해 클래스 간의 메서드 충돌을 해결할 수 있다.
다형성
같은 이름의 메소드나 함수를 호출하더라도 객체의 종류에 따라 서로 다른 방식으로 동작하는 특성이다.
Python은 정적 타입 언어처럼 명시적인 인터페이스 구현을 요구하지 않고 동일한 메소드를 가지고 있으면
타입과 관계없이 사용할 수 있는 덕 타이핑(Duck Typing)을 기반으로 다형성을 자연스럽게 지원한다.
이러한 특징은 새로운 기능을 추가할 때 기존 코드를 수정하지 않아도 되는 장점을 제공한다.
class CashPayment:
def pay(self, amount):
print(f"현금으로 {amount}원 결제합니다")
class KakaoPay:
def pay(self, amount):
print(f"카카오페이로 {amount}원 결제합니다")
def process_payment(payment, amount):
payment.pay(amount)
cash = CashPayment()
kakao = KakaoPay()
process_payment(cash, 10000)
process_payment(kakao, 10000)
추상화
복잡한 내부 구현은 숨기고, 외부에서는 필요한 핵심 기능만 간단하게 사용할 수 있도록 만드는 개념이다.
사용자는 객체가 내부적으로 어떻게 동작하는지 몰라도, 제공된 메소드만으로 기능을 사용할 수 있고
이를 통해 복잡도를 줄이고 이해와 사용을 쉽게 한다.
Python에서는 일반 클래스 설계뿐 아니라 abc module의 ABC와 @abstractmethod을 사용해
추상 클래스를 정의하고 반드시 구현해야 하는 메소드를 강제함으로써 일관된 구조를 유지한다.
즉, "무엇을 할 수 있는지"에 집중하는 설계 방식이다.
from abc import ABC, abstractmethod
class Payment(ABC):
@abstractmethod
def pay(self, amount):
pass
class CardPayment(Payment):
def pay(self, amount):
print(f"카드로 {amount}원 결제합니다")
'AI > Python' 카테고리의 다른 글
| Python의 기본 - 매직 메서드 (11) (0) | 2026.05.23 |
|---|---|
| Python의 기본 - 예외 처리 (10) (0) | 2026.05.23 |
| Python의 기본 - 프로그래밍 방법론 (8) (0) | 2026.05.15 |
| Python의 기본 - 사용자 정의 함수 (7) (0) | 2026.05.14 |
| Python의 기본 - 제어문 (6) (0) | 2026.05.14 |