Menu
Coddy logo textTech

Czym jest polimorfizm?

W programowaniu polimorfizm to zdolność jednego fragmentu kodu, takiego jak wywołanie funkcji albo nazwa metody, do pracy z wartościami różnych typów, z których każdy dostarcza własne zachowanie. Wywołanie shape.area() wykonuje inne obliczenie dla koła, a inne dla kwadratu.

Autor: Kevin Spektor, Współzałożyciel i CTO

Aktualizacja: 24 września 2026

W Pythonie len("hello") zwraca 5, len([4, 8, 15]) zwraca 3, a len({"a": 1}) zwraca 1. To jedna nazwa funkcji użyta na trzech typach, a każdy typ liczy na swój sposób: napis liczy znaki, lista liczy elementy, słownik liczy klucze. Słowo pochodzi z greki: poly, wiele, i morph, forma. Jedno wywołanie, wiele form zachowania.

Jak działa polimorfizm

Kod wywołuje metodę po nazwie, na przykład shape.area(). Gdy ta linia się wykonuje, język patrzy na faktyczny obiekt i szuka area w klasie tego obiektu. To wyszukiwanie nazywa się dynamicznym wiązaniem (dynamic dispatch) i właśnie ono pozwala jednej linii wykonywać różną pracę dla różnych obiektów:

Circle 3.14
Square 9
Circle 12.57

Python znajduje metodę, przeszukując najpierw klasę obiektu, a potem jej klasy nadrzędne w ustalonej kolejności, nazywanej kolejnością rozwiązywania metod (method resolution order). Gdyby Square nie miał własnego area(), wyszukiwanie doszłoby do Shape.area() i zgłosiło NotImplementedError, co jest sygnałem, że każda podklasa musi dostarczyć własną wersję.

Pętla nigdy nie sprawdza, jaką figurę trzyma. Żeby dodać trójkąt, piszesz klasę Triangle z własnym area(), a pętla działa bez zmian. Bez polimorfizmu pętla potrzebowałaby gałęzi if isinstance(...) dla każdej figury, edytowanej za każdym razem, gdy pojawi się nowa.

Rodzaje polimorfizmu

RodzajInna nazwaJak wyglądaKiedy wybierana jest wersja
PodtypowyPolimorfizm dynamiczny, nadpisywanie metodPodklasa zastępuje metodę rodzicaW trakcie działania programu
Ad hocPrzeciążanieJedna nazwa, kilka wersji dla różnych typów parametrów; także przeciążanie operatorówW czasie kompilacji w Javie i C++
ParametrycznyTypy generyczne, szablonyJeden fragment kodu, który działa dla dowolnego typu: List<T> w Javie, vector<T> w C++W czasie kompilacji

Gdy ktoś w programowaniu obiektowym mówi po prostu "polimorfizm", prawie zawsze ma na myśli pierwszy wiersz: polimorfizm podtypowy przez nadpisywanie.

Python ma wszystkie trzy na swój sposób. Nadpisywanie działa jak w przykładzie z figurami. Operatory takie jak + to polimorfizm ad hoc. Funkcje takie jak max() i sorted() są parametryczne w duchu: przyjmują listę liczb, napisów albo dat, o ile elementy da się porównać, a podpowiedzi typów takie jak list[int] albo TypeVar mogą to jawnie zapisać.

Polimorfizm statyczny i dynamiczny w Javie

Java ma oba rodzaje, a pytania na rozmowach kwalifikacyjnych często dotyczą różnicy między nimi:

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

Zmienna pet ma typ Animal, a mimo to wykonuje się wersja z Dog, bo wybór zależy od obiektu, a nie od zmiennej. Dwie metody add to przeciążanie: kompilator wybiera jedną na podstawie typów argumentów, zanim program się uruchomi. Interfejsy dają to samo zachowanie w czasie działania bez współdzielenia kodu: każdą klasę implementującą Comparable można posortować przez Collections.sort. C++ działa tak samo z jedną różnicą: metoda dostaje wiązanie dynamiczne tylko wtedy, gdy jest zadeklarowana jako virtual. Zobacz polimorfizm w Javie, przeciążanie metod i funkcje wirtualne w C++.

Polimorfizm w Pythonie: duck typing i operatory

Python nie wymaga wspólnej klasy nadrzędnej. Jeśli obiekt ma metodę, którą wywołuje kod, to działa: "jeśli chodzi jak kaczka i kwacze jak kaczka, to jest kaczką". Operatory też są polimorficzne. Napisanie a + b wywołuje a.__add__(b), więc twoje własne klasy mogą obsługiwać +, len() i print():

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

Dziedziczenie to jeden ze sposobów na polimorfizm, a nie wymóg. Vector nie dziedziczy po niczym szczególnym, a mimo to len() i + traktują go jak typ wbudowany. Dokumentacja dziedziczenia w Pythonie pokazuje drogę przez podklasy.

Częste błędy

Oczekiwanie, że Python przeciąża według sygnatury. Drugie def o tej samej nazwie po cichu zastępuje pierwsze:

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

Zamiast tego użyj argumentu domyślnego: def greet(first, last="").

Zapominanie o virtual w C++. Bez niego wywołanie metody przez wskaźnik do klasy bazowej uruchamia wersję bazową, nawet gdy obiekt jest podklasą.

Nadpisania, które zmieniają znaczenie. Jeśli area() w jednej podklasie zwraca obwód, psuje się każdy kod, który ufa area(). Nadpisanie musi dotrzymać obietnicy złożonej przez rodzica; ta reguła nazywa się zasadą podstawienia Liskov.

Sprawdzanie typów wszędzie. Łańcuch gałęzi if type(x) == ... zwykle oznacza, że każdy typ powinien zamiast tego mieć własną metodę.

Co dalej

Polimorfizm działa razem z enkapsulacją, która chroni dane każdego obiektu, i abstrakcją, która definiuje wspólny interfejs implementowany przez typy. Poćwicz nadpisywanie w dokumentacji klas w Pythonie albo wypróbuj kurs Java, gdzie przeciążanie i nadpisywanie pojawiają się obok siebie.

Najczęściej zadawane pytania

Jaki jest przykład polimorfizmu?
Operator + w Pythonie: 1 + 2 dodaje liczby, "ab" + "cd" łączy napisy, a [1] + [2] łączy listy. Ten sam symbol działa na trzech typach, a każdy typ decyduje, co on oznacza. W kodzie obiektowym klasycznym przykładem jest lista figur, w której każda odpowiada na area() własnym wzorem.
Czym różni się polimorfizm od dziedziczenia?
Dziedziczenie pozwala klasie ponownie wykorzystać kod klasy nadrzędnej. Polimorfizm pozwala kodowi traktować różne typy przez jeden wspólny interfejs. Dziedziczenie to jeden z popularnych sposobów na uzyskanie polimorfizmu, bo podklasa może nadpisać metodę rodzica, ale duck typing w Pythonie i interfejsy w Javie dają polimorfizm bez współdzielenia jakiegokolwiek kodu.
Czym jest polimorfizm w biologii?
W biologii polimorfizm oznacza, że w tej samej populacji występują dwie lub więcej form cechy albo genu, na przykład grupy krwi A, B, AB i 0 u ludzi. Ma ten sam grecki źródłosłów, "wiele form", co termin programistyczny, ale oba pojęcia nie są ze sobą związane.
Czy Python obsługuje przeciążanie metod?
Nie według typów ani liczby parametrów, jak robią to Java i C++. Drugie def o tej samej nazwie zastępuje pierwsze. Kod w Pythonie osiąga ten sam efekt za pomocą argumentów domyślnych, *args albo functools.singledispatch, który wybiera funkcję na podstawie typu pierwszego argumentu.
Dlaczego polimorfizm jest przydatny?
Pozwala dodawać nowe typy bez zmieniania kodu, który ich używa. Program do rysowania, który wywołuje shape.draw() na każdej figurze, nie wymaga żadnych zmian, gdy dodasz klasę trójkąta; pisze się tylko nową klasę. Bez polimorfizmu ta pętla dostawałaby nową gałąź if dla każdego typu.
Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ