all Python 3OOPterm
Polymorphism
polymorphism
One interface — different implementations. In Python it comes from overriding methods and from duck typing.
Syntax
for obj in objects:
obj.method() # разные реализации
In Python objects need no common ancestor — matching method names are enough (duck typing), so polymorphism works with no inheritance at all. A base class raising NotImplementedError is only a convention; to have a missing method caught when the object is created rather than when it's called, use abc.ABC with @abstractmethod.
Examples
class Shape:
def area(self):
raise NotImplementedError
class Circle(Shape):
def __init__(self, r):
self.r = r
def area(self):
import math
return math.pi * self.r**2
class Rectangle(Shape):
def __init__(self, w, h):
self.w = w; self.h = h
def area(self):
return self.w * self.h
shapes = [Circle(3), Rectangle(4,5)]
for s in shapes:
print(round(s.area(), 2)) # → 28.27 / 20
# Duck typing
class Dog:
def speak(self):
return 'Woof!'
class Cat:
def speak(self):
return 'Meow!'
class Duck:
def speak(self):
return 'Quack!'
for animal in [Dog(), Cat(), Duck()]:
print(animal.speak()) # → Woof! Meow! Quack!
# Общая функция — полиморфный вызов
def make_sound(animal):
print(animal.speak())
make_sound(Dog()) # → Woof!
make_sound(Duck()) # → Quack!
# Перегрузка операторов — полиморфизм
class Vector:
def __init__(self, x):
self.x = x
def __add__(self, other):
return Vector(self.x + other.x)
class Matrix:
def __init__(self, data):
self.data = data
def __add__(self, other):
return Matrix([[a + b for a, b in zip(r1, r2)]
for r1, r2 in zip(self.data, other.data)])
print((Vector(1)+Vector(2)).x) # → 3
# isinstance + полиморфизм
def describe(obj):
if isinstance(obj, list):
return f'list of {len(obj)}'
elif isinstance(obj, str):
return f'string: {obj!r}'
else:
return f'other: {type(obj).__name__}'
print(describe([1,2,3])) # → list of 3
print(describe('hi')) # → string: 'hi'
See also
Open in the full glossarydocs.python.orgReport an inaccuracy