파이썬 객체지향 프로그래밍의 다형성과 고급 특성

1. 다형성 개념

다형성이란 동일한 타입이 다양한 형태를 가질 수 있는 특성을 의미합니다.

예를 들어 동물이라는 개념은 사람, 원숭이, 오리 등 다양한 형태로 존재할 수 있습니다.

1.1 코드 구현 예제

from abc import ABC, abstractmethod

class LivingBeing(ABC):
    @abstractmethod
    def move(self):
        pass

    @abstractmethod
    def communicate(self, identity):
        print(f'{identity}가 소통 중입니다')

class Human(LivingBeing):
    def move(self):
        print('사람은 걷습니다')

    def communicate(self, identity):
        print(f'{identity}가 말하고 있습니다')

class Primate(LivingBeing):
    def move(self):
        print('원숭이는 트립니다')

class Waterfowl(LivingBeing):
    def move(self):
        print('오리는 헤엄칩니다')

1.2 다형성의 특징

동적 바인딩: 런타임 시점에 객체의 실제 타입에 따라 적절한 메서드를 연결하는 방식입니다.

동적 다형성: 상속 관계에서 동적 바인딩을 활용한 다형성입니다.

정적 다형성: 연산자 오버로딩처럼 컴파일 시점에 결정되는 다형성입니다.

from abc import ABC, abstractmethod

class Creature(ABC):
    @abstractmethod
    def move(self):
        pass

class Human(Creature):
    def move(self):
        print('사람은 걷습니다')

class Primate(Creature):
    def move(self):
        print('원숭이는 트립니다')

class Waterfowl(Creature):
    def move(self):
        print('오리는 헤엄칩니다')

individual1 = Human()
individual2 = Primate()
individual3 = Waterfowl()

individual1.move()
individual2.move()
individual3.move()

def execute_movement(entity):
    entity.move()

파이썬은 모든 것이 객체이기 때문에 기본적으로 다형성을 지원합니다.

# 객체 타입에 관계없이 길이를 측정
obj1.__len__()
obj2.__len__()
obj3.__len__()

# 파이썬은 통합된 인터페이스 제공
len(obj1)
len(obj2)
len(obj3)

2. 덕 타이핑

덕 타이핑(Duck Typing)은 실제 타입보다는 행동에 초점을 맞춘 프로그래밍 패러다임입니다.

"오리처럼 걷고, 오리처럼 꽥꽥거린다면 그것은 오리다"라는 철학을 따릅니다.

class TextFile:
    def read(self):
        pass

    def write(self):
        pass

class MediaFile:
    def read(self):
        pass

    def write(self):
        pass

# 두 클래스 모두 파일과 유사한 인터페이스를 가지고 있어 파일처럼 사용 가능

3. 메서드 바인딩 종류

3.1 바인딩 메서드

개념: 호출 주체에 따라 자동으로 첫 번째 파라미터로 자신을 전달하는 메서드입니다.

  • 객체에 바인딩된 메서드
  • 클래스에 바인딩된 메서드

3.2 인스턴스 메서드

클래스 내부에 정의된 일반적인 메서드로, 자동으로 self 파라미터를 처리합니다.

class Learner:
    def __init__(self, identifier):
        self.identifier = identifier

    def study(self):
        print(f'{self.identifier}가 학습 중입니다')

student1 = Learner(identifier='kim')

# 인스턴스를 통해 호출 - self 자동 전달
student1.study()

# 클래스를 통해 호출 - 명시적으로 인스턴스 전달 필요
student2 = Learner(identifier='lee')
Learner.study(student1)
Learner.study(student2)

3.3 클래스 메서드

@classmethod 데코레이터를 사용하며, 첫 번째 파라미터로 클래스 자체를 받습니다.

class Learner:
    def __init__(self, identifier):
        self.identifier = identifier

    @classmethod
    def get_info(cls):
        print(f'현재 클래스: {cls}')

# 인스턴스 호출 - 클래스 정보 자동 전달
student1 = Learner(identifier='kim')
student1.get_info()

# 클래스 직접 호출
Learner.get_info()

3.4 정적 메서드

@staticmethod 데코레이터를 사용하며, 어떤 파라미터도 자동으로 전달되지 않습니다.

class Learner:
    def __init__(self, level):
        self.level = level

    @staticmethod
    def calculate_grade(score):
        return score * 10

# 인스턴스와 클래스 모두를 통해 호출 가능
student1 = Learner(level=3)
result1 = student1.calculate_grade(85)
result2 = Learner.calculate_grade(90)

4. 리플렉션

4.1 리플렉션 메서드

hasattr(obj, name)      # 속성 존재 여부 확인
getattr(obj, name[, default])  # 속성 값 가져오기
setattr(obj, name, value)      # 속성 값 설정
delattr(obj, name)      # 속성 삭제

4.2 hasattr 예제

class Learner:
    def __init__(self, name, level):
        self.name = name
        self.level = level

    def study(self):
        print('학습 메서드')

    @classmethod
    def show_class(cls):
        print('클래스 메서드')

    @staticmethod
    def utility():
        print('유틸리티 메서드')

student1 = Learner(name='kim', level=2)

print(hasattr(student1, 'name'))     # True
print(hasattr(student1, 'hobby'))    # False
print(hasattr(student1, 'utility'))  # True

4.3 getattr 예제

student1 = Learner(name='kim', level=2)

print(getattr(student1, 'name'))
print(getattr(student1, 'hobby', '없음'))

# 메서드 접근 및 실행
method_ref = getattr(student1, 'utility')
method_ref()

4.4 setattr 예제

student1 = Learner(name='kim', level=2)
print(student1.__dict__)

# 새로운 속성 추가
setattr(student1, 'interest', 'python')
print(student1.__dict__)

# 기존 속성 수정
setattr(student1, 'interest', 'java')
print(student1.__dict__)

4.5 delattr 예제

student1 = Learner(name='kim', level=2)
print(student1.__dict__)

delattr(student1, 'level')
print(student1.__dict__)

5. 매직 메서드

5.1 초기화 및 소멸

class Learner:
    def __init__(self, name):
        self.name = name
        print('__init__ 실행됨')

    def __del__(self):
        print("객체 해제됨")

student1 = Learner(name='kim')

5.2 문자열 표현

class Learner:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return f'{self.name} 학생'

student1 = Learner(name='kim')
print(student1)

5.3 문서화

class Learner:
    """
    학습자 정보를 관리하는 클래스
    """
    def __init__(self, name):
        self.name = name

print(Learner.__doc__)

5.4 속성 접근 제어

class Learner:
    def __init__(self, name):
        self.name = name

    def __getattr__(self, key):
        return f'{key} 속성이 없습니다'

    def __setattr__(self, key, value):
        print(f'{key}: {value} 설정됨')

    def __delattr__(self, key):
        print(f'{key} 속성 삭제됨')

student1 = Learner(name='kim')
print(student1.age)
student1.skill = 'coding'
del student1.name

5.5 인덱싱 연산

class Learner:
    def __init__(self, name):
        self.name = name

    def __getitem__(self, key):
        return f'{self.name}의 {key} 정보'

    def __setitem__(self, key, value):
        print(f'{key}: {value} 저장됨')

    def __delitem__(self, key):
        print(f'{key} 항목 삭제됨')

student1 = Learner(name='kim')
print(student1['성적'])
student1['나이'] = 20
del student1['성적']

태그: python OOP Polymorphism duck-typing class-methods

7월 22일 17:22에 게시됨