다형성 — 객체 지향 프로그래밍의 근본 원칙으로, 구조가 다른 객체들이 동일한 인터페이스를 구현하게 하여 상호 교환되도록 합니다. 파이썬의 동적 타이핑에서는 다형성이 매우 유연하게 구성됩니다.
엄격한 정적 타이핑 언어(Java, C++)에서는 다형성을 지원하기 위해 인터페이스나 추상 클래스를 선언해야 합니다. 반면, 파이썬에서는 duck typing 덕분에 다형성이 상속 계층이나 인터페이스에 얽매이지 않습니다. 주요 사항은 객체가 필요한 메서드/속성을 지원하는 것입니다.
한편으로는, 이것이 언어를 유연하고 편리하게 만들지만 다른 한편으로는 오타나 필요한 메서드의 부재로 인해 발생하는 런타임 오류의 가능성이 증가합니다. 이러한 오류는 코드 실행 시에만 나타납니다.
파이썬에서는 다음과 같은 다형성을 구분합니다:
class Animal: def speak(self): raise NotImplementedError class Dog(Animal): def speak(self): return 'Woof!' class Cat(Animal): def speak(self): return 'Meow!' def animal_voice(animal): print(animal.speak()) animal_voice(Dog()) # Woof! animal_voice(Cat()) # Meow!
class Duck: def quack(self): return 'Quack!' def make_quack(animal): print(animal.quack()) make_quack(Duck()) # Quack!
주요 특징:
상속이 파이썬에서 다형성을 보장하는 유일한 방법인가요?
아닙니다. duck typing 덕분에 어떤 함수도 그 메서드가 필요한 객체를 클래스나 계층과 상관없이 받을 수 있습니다.
메서드의 본질이 아니라 메서드 이름만 일치하는 것을 다형성으로 간주할 수 있나요?
아닙니다. 객체가 필요한 메서드를 지원하지만 그 의미가 예상과 다르면 버그가 발생할 수 있습니다. 다형성은 인터페이스뿐만 아니라 의미가 일치할 때만 성공적입니다.
추상 클래스가 자식 클래스의 잘못된 인터페이스 구현으로 인한 오류를 방지할 수 있나요?
부분적으로만 가능합니다. 상속자가 추상 메서드를 구현하지 않으면 인스턴스를 생성하려 할 때 TypeError가 발생하지만, 논리를 위반하여 구현 시도 시에는 여전히 오류가 발생할 수 있습니다.
로깅 라이브러리에 외부 클래스를 도입했을 때, log() 메서드가 있지만 데이터를 반환하고 로그를 기록하지 않는 경우입니다. 오류는 사용 시점에만 나타납니다.
장점:
단점:
클래스에 테스트를 추가하고, 인터페이스를 추상 기본 클래스와 @abstractmethod를 통해 형식적으로 정의하며, 문서화 과정에서 메서드의 의미를 명시합니다.
장점:
단점: