ProgrammingPython Developer

Explain how polymorphism is implemented in Python, what forms exist, and what are the nuances of dynamic typing in practice?

Pass interviews with Hintsage AI assistant

Answer.

Polymorphism is a fundamental principle of object-oriented programming that allows objects with different structures to implement the same interface, meaning they can work interchangeably. In Python, with dynamic typing, polymorphism is quite flexible.

Background

In languages with strict static typing (Java, C++), support for polymorphism requires declaring interfaces or abstract classes. In Python, thanks to duck typing, polymorphism is not tied to the inheritance hierarchy or even an interface. The main requirement is that the object supports the necessary methods/attributes.

Problem

On one hand, this makes the language flexible and convenient. On the other hand, it increases the likelihood of runtime errors due to typos or the absence of a necessary method, which only manifest when the code is executed.

Solution

In Python, there are:

  • Regular (classical) polymorphism through inheritance and method overriding:
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!
  • Duck Typing — if a class has the necessary method, it is suitable for any function expecting that method, regardless of its parentage:
class Duck: def quack(self): return 'Quack!' def make_quack(animal): print(animal.quack()) make_quack(Duck()) # Quack!
  • Interface emulation — through abc.ABC and @abstractmethod, it can be formalized that classes must implement certain methods.

Key features:

  • No obligation to maintain a rigid inheritance hierarchy.
  • The ability to substitute objects at runtime if they support the required interface.
  • Interface mismatch errors only surface during execution.

Trick Questions.

Is inheritance the only way to ensure polymorphism in Python?

No. Thanks to duck typing, any function can accept an object with the necessary methods, regardless of its class or hierarchy.

Can matching a signature by method name alone be considered polymorphism, rather than its essence?

No. If an object supports the needed method but its semantics differ from what is expected — bugs can occur. Polymorphism is successful only when both the interface and the meaning match.

Does an abstract class provide protection against errors of incorrectly implemented interfaces in child classes?

Only partially. If a descendant does not implement the abstract method — a TypeError will occur when trying to create an instance. But if it implements it with a logic violation — errors are possible.

Typical errors and anti-patterns

  • Incorrect implementation of an interface without following the semantics of the method.
  • Relying on duck typing without adequate tests, leading to runtime errors.
  • Expecting strict typing (as in statically typed languages), even though Python does not guarantee this.

Real-life Example

Negative Case

An external class with a log() method is integrated into the logging library, but it returns a data object instead of writing to the log. Errors appear only during operation.

Pros:

  • Quick integration of various classes without unnecessary bureaucracy.

Cons:

  • Silent bugs that are only detected at runtime, often already in production.

Positive Case

Classes are equipped with tests, the interface is formalized through an abstract base class and @abstractmethod, and the semantics of methods are documented.

Pros:

  • Explicitness, preventing the most common errors.
  • Increased reliability of the code.

Cons:

  • A more strict development discipline, more code and documentation.