Menu
Coddy logo textTech

Что такое полиморфизм?

В программировании полиморфизм это способность одного фрагмента кода, например вызова функции или имени метода, работать со значениями разных типов, где каждый тип задаёт своё поведение. Вызов shape.area() выполняет для круга другое вычисление, чем для квадрата.

Автор: Kevin Spektor, Сооснователь и CTO

Обновлено 24 сентября 2026 г.

В Python len("hello") возвращает 5, len([4, 8, 15]) возвращает 3, а len({"a": 1}) возвращает 1. Это одно имя функции для трёх типов, и каждый тип считает по-своему: строка считает символы, список элементы, словарь ключи. Слово пришло из греческого: poly, много, и morph, форма. Один вызов, много форм поведения.

Как работает полиморфизм

Код вызывает метод по имени, например shape.area(). Когда эта строка выполняется, язык смотрит на фактический объект и находит area в классе самого объекта. Такой поиск называется динамической диспетчеризацией, и именно он позволяет одной строке выполнять разную работу для разных объектов:

Circle 3.14
Square 9
Circle 12.57

Python ищет метод сначала в классе объекта, потом в его родительских классах в определённом порядке, который называется порядком разрешения методов (MRO). Если бы у Square не было своего area(), поиск дошёл бы до Shape.area() и выбросил бы NotImplementedError, сигнал о том, что каждый подкласс должен реализовать этот метод.

Цикл никогда не проверяет, какая фигура у него в руках. Чтобы добавить треугольник, ты пишешь класс Triangle с собственным area(), и цикл работает без изменений. Без полиморфизма циклу понадобилась бы ветка if isinstance(...) для каждой фигуры, и её пришлось бы править всякий раз, когда появляется новая.

Виды полиморфизма

ВидДругие названияКак выглядитКогда выбирается версия
Полиморфизм подтиповДинамический полиморфизм, переопределение методовПодкласс заменяет метод родителяВо время работы программы
Ad hocПерегрузкаОдно имя, несколько версий для разных типов параметров; сюда же перегрузка операторовВо время компиляции в Java и C++
ПараметрическийОбобщения (generics), шаблоныОдин фрагмент кода, который работает с любым типом: List<T> в Java, vector<T> в C++Во время компиляции

Когда в объектно-ориентированном программировании говорят «полиморфизм» без уточнений, почти всегда имеют в виду первую строку: полиморфизм подтипов через переопределение.

В Python есть все три, каждый на свой лад. Переопределение работает, как в примере с фигурами. Операторы вроде + это ad hoc полиморфизм. Функции вроде max() и sorted() параметрические по духу: они принимают список чисел, строк или дат, лишь бы элементы можно было сравнивать, а аннотации типов вроде list[int] или TypeVar позволяют указать это явно.

Статический и динамический полиморфизм в Java

В Java есть оба вида, и на собеседованиях часто спрашивают о разнице:

class Animal { String sound() { return "..."; } }
class Dog extends Animal {
    @Override String sound() { return "Woof"; }
}

Animal pet = new Dog();
pet.sound();          // "Woof": chosen at run time from the object

int add(int a, int b)          { return a + b; }
double add(double a, double b) { return a + b; }
add(2, 3);            // int version, chosen by the compiler
add(2.5, 1.0);        // double version

Переменная pet имеет тип Animal, но выполняется версия Dog, потому что выбор зависит от объекта, а не от переменной. Два метода add это перегрузка: компилятор выбирает один из них по типам аргументов ещё до запуска программы. Интерфейсы дают то же поведение во время выполнения без общего кода: любой класс, реализующий Comparable, можно отсортировать с помощью Collections.sort. C++ работает так же с одним отличием: метод получает динамическую диспетчеризацию, только если он объявлен как virtual. Смотри полиморфизм в Java, перегрузку методов и виртуальные функции C++.

Полиморфизм в Python: утиная типизация и операторы

Python не требует общего родительского класса. Если у объекта есть метод, который вызывает код, всё работает: «если что-то ходит как утка и крякает как утка, это утка». Операторы тоже полиморфны. Запись a + b вызывает a.__add__(b), поэтому твои собственные классы могут поддерживать +, len() и print():

3 abcd [1, 2]
Vector(11, 22)
5 3 2

Наследование это один из способов получить полиморфизм, а не обязательное условие. Vector ни от чего особенного не наследуется, но len() и + обращаются с ним как со встроенным типом. Документация по наследованию в Python показывает путь через подклассы.

Частые ошибки

Ожидание, что Python перегружает функции по сигнатуре. Второй def с тем же именем молча заменяет первый:

Hi Ana Silva
Traceback (most recent call last):
  ...
TypeError: greet() missing 1 required positional argument: 'last'

Вместо этого используй аргумент по умолчанию: def greet(first, last="").

Забытый virtual в C++. Без него вызов метода через указатель на базовый класс выполняет базовую версию, даже если объект это подкласс.

Переопределения, которые меняют смысл. Если area() в одном подклассе возвращает периметр, ломается каждый вызывающий код, который доверяет area(). Переопределение должно выполнять обещание, данное родителем; это правило известно как принцип подстановки Лисков.

Проверки типов повсюду. Цепочка веток if type(x) == ... обычно говорит о том, что у каждого типа должен быть свой метод.

Что читать дальше

Полиморфизм работает вместе с инкапсуляцией, которая защищает данные каждого объекта, и абстракцией, которая задаёт общий интерфейс, реализуемый типами. Потренируйся в переопределении по документации по классам Python или попробуй курс Java, где перегрузка и переопределение встречаются бок о бок.

Часто задаваемые вопросы

Какой пример полиморфизма самый простой?
Оператор + в Python: 1 + 2 складывает числа, "ab" + "cd" соединяет строки, а [1] + [2] соединяет списки. Один и тот же символ работает с тремя типами, и каждый тип сам решает, что он означает. В объектно-ориентированном коде классический пример это список фигур, где каждая отвечает на area() по своей формуле.
Чем полиморфизм отличается от наследования?
Наследование позволяет классу повторно использовать код родительского класса. Полиморфизм позволяет коду работать с разными типами через один общий интерфейс. Наследование это один из распространённых способов получить полиморфизм, потому что подкласс может переопределить метод родителя, но утиная типизация в Python и интерфейсы в Java дают полиморфизм без всякого общего кода.
Что такое полиморфизм в биологии?
В биологии полиморфизм означает, что в одной популяции существуют две или больше формы признака или гена, например группы крови A, B, AB и O у людей. У него тот же греческий корень, «много форм», что и у термина из программирования, но эти понятия не связаны.
Поддерживает ли Python перегрузку методов?
Не по типам или количеству параметров, как Java и C++. Второй def с тем же именем заменяет первый. В коде на Python тот же эффект получают с помощью аргументов по умолчанию, *args или functools.singledispatch, который выбирает функцию по типу первого аргумента.
Зачем нужен полиморфизм?
Он позволяет добавлять новые типы, не меняя код, который ими пользуется. Программе для рисования, которая вызывает shape.draw() для каждой фигуры, не нужны правки, когда ты добавляешь класс треугольника; пишется только новый класс. Без полиморфизма в этом цикле появлялась бы новая ветка if для каждого типа.
Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ