Witaj znowu, @name! Darwin tutaj z fascynującym tematem.
W poprzednich lekcjach nauczyłeś/aś się tworzyć klasy reprezentujące gatunki. Ale w naturze gatunki nie są izolowane - są częścią hierarchii taksonomicznej! Lwy i tygrysy to różne gatunki, ale oba są kotowatymi. Kotowate i psowate to różne rodziny, ale oba są ssakami.
W programowaniu obiektowym ta hierarchia to dziedziczenie (inheritance) - jeden z najpo tężniejszych mechanizmów OOP!
Dziedziczenie pozwala tworzyć nowe klasy na podstawie istniejących:
Klasa pochodna dziedziczy atrybuty i metody klasy bazowej, a następnie może:
1# Klasa bazowa - ogólny Ssak
2class Mammal:
3 def __init__(self, name):
4 self.name = name
5
6 def breathe(self):
7 return f"{self.name} oddycha powietrzem"
8
9 def move(self):
10 return f"{self.name} porusza się"
11
12# Klasa pochodna - Lew dziedziczy z Mammal
13class Lion(Mammal):
14 def __init__(self, name, pride_name):
15 super().__init__(name) # Wywołaj konstruktor rodzica
16 self.pride_name = pride_name # Dodaj własny atrybut
17
18 def roar(self):
19 """Nowa metoda - tylko dla lwów"""
20 return f"{self.name} ryczy: RRROAAR!"
21
22 def move(self):
23 """Nadpisanie metody rodzica"""
24 return f"{self.name} biegnie przez sawannę"
25
26# Użycie
27simba = Lion("Simba", "Pride Rock")
28
29# Dziedziczone z Mammal
30print(simba.breathe()) # "Simba oddycha powietrzem"
31
32# Nadpisane w Lion
33print(simba.move()) # "Simba biegnie przez sawannę"
34
35# Własna metoda Lion
36print(simba.roar()) # "Simba ryczy: RRROAAR!"
37
38# Własny atrybut Lion
39print(simba.pride_name) # "Pride Rock"1# Podstawowa składnia
2class ChildClass(ParentClass):
3 pass
4
5# Dziedziczenie z rozszerzeniem
6class Animal:
7 def eat(self):
8 return "Jem"
9
10class Dog(Animal): # Dog dziedziczy z Animal
11 def bark(self):
12 return "Hau hau!"
13
14dog = Dog()
15print(dog.eat()) # Dziedziczone: "Jem"
16print(dog.bark()) # Własne: "Hau hau!"super()
pozwala odwołać się do klasy bazowej - używaj jej do:super()
1class Animal:
2 def __init__(self, name, age):
3 self.name = name
4 self.age = age
5 print(f"Tworzę zwierzę: {name}")
6
7 def describe(self):
8 return f"{self.name}, wiek: {self.age}"
9
10class Bird(Animal):
11 def __init__(self, name, age, wingspan):
12 # Wywołaj konstruktor Animal
13 super().__init__(name, age)
14 # Dodaj własny atrybut
15 self.wingspan = wingspan
16 print(f"Rozpiętość skrzydeł: {wingspan}m")
17
18 def describe(self):
19 # Rozszerz metodę rodzica
20 base_desc = super().describe() # Wywołaj Animal.describe()
21 return f"{base_desc}, rozpiętość: {self.wingspan}m"
22
23eagle = Bird("Orzeł", 5, 2.3)
24# Drukuje:
25# Tworzę zwierzę: Orzeł
26# Rozpiętość skrzydeł: 2.3m
27
28print(eagle.describe())
29# "Orzeł, wiek: 5, rozpiętość: 2.3m"Klasa pochodna może całkowicie zastąpić metodę rodzica:
1class Animal:
2 def speak(self):
3 return "Zwierzę wydaje dźwięk"
4
5class Dog(Animal):
6 def speak(self):
7 """Nadpisz całkowicie"""
8 return "Hau hau!" # Całkowicie nowe zachowanie
9
10class Cat(Animal):
11 def speak(self):
12 """Nadpisz całkowicie"""
13 return "Miau!"
14
15dog = Dog()
16cat = Cat()
17
18print(dog.speak()) # "Hau hau!" - nie "Zwierzę wydaje dźwięk"
19print(cat.speak()) # "Miau!"W naturze hierarchia jest głęboka: Królestwo → Typ → Klasa → Rząd → Rodzina → Rodzaj → Gatunek
1# 1. Królestwo Animalia
2class Animal:
3 kingdom = "Animalia"
4
5 def __init__(self, name):
6 self.name = name
7
8 def is_alive(self):
9 return True
10
11 def __str__(self):
12 return f"{self.name} ({self.__class__.__name__})"
13
14# 2. Typ Chordata
15class Chordate(Animal):
16 phylum = "Chordata"
17
18 def has_backbone(self):
19 return True
20
21# 3. Klasa Mammalia (Ssaki)
22class Mammal(Chordate):
23 class_name = "Mammalia"
24
25 def __init__(self, name, fur_color):
26 super().__init__(name)
27 self.fur_color = fur_color
28
29 def nurse_young(self):
30 return f"{self.name} karmi młode mlekiem"
31
32 def regulate_temperature(self):
33 return f"{self.name} utrzymuje stałą temperaturę ciała"
34
35# 4. Rząd Carnivora (Drapieżniki)
36class Carnivore(Mammal):
37 order = "Carnivora"
38
39 def __init__(self, name, fur_color, hunting_style):
40 super().__init__(name, fur_color)
41 self.hunting_style = hunting_style
42
43 def hunt(self):
44 return f"{self.name} poluje używając: {self.hunting_style}"
45
46# 5. Rodzina Felidae (Kotowate)
47class Feline(Carnivore):
48 family = "Felidae"
49
50 def retract_claws(self):
51 return f"{self.name} chowa pazury"
52
53 def purr(self):
54 return f"{self.name} mruczy"
55
56# 6. Gatunek Panthera leo (Lew)
57class Lion(Feline):
58 species = "Panthera leo"
59
60 def __init__(self, name, fur_color, pride_name):
61 super().__init__(name, fur_color, "polowanie stadne")
62 self.pride_name = pride_name
63
64 def roar(self):
65 return f"{self.name} ryczy głośno!"
66
67 def lead_pride(self):
68 return f"{self.name} przewodzi stadzie {self.pride_name}"
69
70# Użycie - lew ma dostęp do WSZYSTKICH metod hierarchii!
71simba = Lion("Simba", "złoty", "Pride Rock")
72
73# Z Animal
74print(simba.is_alive()) # True
75
76# Z Chordate
77print(simba.has_backbone()) # True
78
79# Z Mammal
80print(simba.nurse_young()) # "Simba karmi młode mlekiem"
81print(simba.regulate_temperature()) # "Simba utrzymuje stałą temperaturę ciała"
82
83# Z Carnivore
84print(simba.hunt()) # "Simba poluje używając: polowanie stadne"
85
86# Z Feline
87print(simba.retract_claws()) # "Simba chowa pazury"
88print(simba.purr()) # "Simba mruczy"
89
90# Własne Lion
91print(simba.roar()) # "Simba ryczy głośno!"
92print(simba.lead_pride()) # "Simba przewodzi stadzie Pride Rock"
93
94# Atrybuty
95print(simba.kingdom) # "Animalia"
96print(simba.species) # "Panthera leo"
97print(simba.fur_color) # "złoty"Python oferuje funkcje do sprawdzania hierarchii:
1class Animal:
2 pass
3
4class Mammal(Animal):
5 pass
6
7class Lion(Mammal):
8 pass
9
10simba = Lion()
11
12# isinstance() - sprawdź czy obiekt jest instancją klasy
13print(isinstance(simba, Lion)) # True
14print(isinstance(simba, Mammal)) # True - Lion dziedziczy z Mammal
15print(isinstance(simba, Animal)) # True - Lion dziedziczy z Animal (przez Mammal)
16print(isinstance(simba, str)) # False
17
18# issubclass() - sprawdź czy klasa dziedziczy z innej klasy
19print(issubclass(Lion, Mammal)) # True
20print(issubclass(Lion, Animal)) # True
21print(issubclass(Mammal, Lion)) # False
22print(issubclass(Lion, Lion)) # True - klasa jest podklasą samej siebie
23
24# type() - zwróć dokładny typ
25print(type(simba)) # <class '__main__.Lion'>
26print(type(simba) == Lion) # True
27print(type(simba) == Mammal) # False - simba to Lion, nie MammalPython pozwala dziedziczyć z wielu klas naraz - klasa może mieć wielu rodziców!
1class Swimmer:
2 def swim(self):
3 return f"{self.name} pływa"
4
5class Flyer:
6 def fly(self):
7 return f"{self.name} lata"
8
9class Walker:
10 def walk(self):
11 return f"{self.name} chodzi"
12
13# Duck dziedziczy z trzech klas!
14class Duck(Swimmer, Flyer, Walker):
15 def __init__(self, name):
16 self.name = name
17
18 def quack(self):
19 return f"{self.name}: Kwa kwa!"
20
21donald = Duck("Donald")
22
23# Ma dostęp do metod ze wszystkich klas bazowych
24print(donald.swim()) # "Donald pływa"
25print(donald.fly()) # "Donald lata"
26print(donald.walk()) # "Donald chodzi"
27print(donald.quack()) # "Donald: Kwa kwa!"Gdy klasa dziedziczy z wielu rodziców, Python używa MRO (Method Resolution Order), aby określić kolejność szukania metod:
1class A:
2 def method(self):
3 return "A"
4
5class B(A):
6 def method(self):
7 return "B"
8
9class C(A):
10 def method(self):
11 return "C"
12
13class D(B, C): # Dziedziczy z B i C
14 pass
15
16d = D()
17print(d.method()) # "B" - Python szuka: D → B → C → A
18
19# Sprawdź MRO
20print(D.__mro__)
21# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>,
22# <class '__main__.A'>, <class 'object'>)
23
24# Lub czytelniej:
25print(D.mro())Zasada: Python przeszukuje klasy od lewej do prawej, od najbardziej specyficznej do najbardziej ogólnej.
1class Species:
2 """
3 Klasa bazowa dla wszystkich gatunków w katalogu Safari
4 """
5
6 kingdom = "Animalia"
7 total_species_count = 0
8
9 def __init__(self, scientific_name, common_name, habitat):
10 self.scientific_name = scientific_name
11 self.common_name = common_name
12 self.habitat = habitat
13 self.observations = []
14
15 Species.total_species_count += 1
16
17 def add_observation(self, date, location, count, notes=""):
18 """Dodaj obserwację w terenie"""
19 self.observations.append({
20 "date": date,
21 "location": location,
22 "count": count,
23 "notes": notes
24 })
25
26 def get_total_observed(self):
27 """Łączna liczba zaobserwowanych osobników"""
28 return sum(obs["count"] for obs in self.observations)
29
30 def describe(self):
31 """Podstawowy opis gatunku"""
32 return f"{self.common_name} ({self.scientific_name})"
33
34 def __str__(self):
35 return self.describe()
36
37class Mammal(Species):
38 """
39 Klasa reprezentująca ssaki - rozszerza Species
40 """
41
42 class_name = "Mammalia"
43
44 def __init__(self, scientific_name, common_name, habitat, fur_color, gestation_days):
45 # Wywołaj konstruktor Species
46 super().__init__(scientific_name, common_name, habitat)
47 # Dodaj atrybuty specyficzne dla ssaków
48 self.fur_color = fur_color
49 self.gestation_days = gestation_days
50
51 def nurse_young(self):
52 """Ssaki karmią młode mlekiem"""
53 return f"{self.common_name} karmi młode mlekiem przez {self.gestation_days // 30} miesięcy"
54
55 def describe(self):
56 """Rozszerz opis o informacje o ssakach"""
57 base = super().describe() # Wywołaj Species.describe()
58 return f"{base} | Ssak | Futro: {self.fur_color}"
59
60class Bird(Species):
61 """
62 Klasa reprezentująca ptaki
63 """
64
65 class_name = "Aves"
66
67 def __init__(self, scientific_name, common_name, habitat, wingspan_m, can_fly=True):
68 super().__init__(scientific_name, common_name, habitat)
69 self.wingspan_m = wingspan_m
70 self.can_fly = can_fly
71
72 def lay_eggs(self):
73 return f"{self.common_name} składa jaja"
74
75 def describe(self):
76 base = super().describe()
77 flight_status = "latający" if self.can_fly else "nielotny"
78 return f"{base} | Ptak {flight_status} | Rozpiętość: {self.wingspan_m}m"
79
80class Carnivore(Mammal):
81 """
82 Drapieżniki - dziedziczą z Mammal
83 """
84
85 order = "Carnivora"
86
87 def __init__(self, scientific_name, common_name, habitat, fur_color,
88 gestation_days, hunting_style, pack_hunter=False):
89 super().__init__(scientific_name, common_name, habitat, fur_color, gestation_days)
90 self.hunting_style = hunting_style
91 self.pack_hunter = pack_hunter
92
93 def hunt(self):
94 style = "w stadzie" if self.pack_hunter else "samotnie"
95 return f"{self.common_name} poluje {style} używając: {self.hunting_style}"
96
97 def calculate_danger_level(self):
98 """Oblicz poziom niebezpieczeństwa (1-10)"""
99 base_danger = 5
100 if self.pack_hunter:
101 base_danger += 3
102 if "zasadzka" in self.hunting_style:
103 base_danger += 2
104 return min(10, base_danger)
105
106 def describe(self):
107 base = super().describe()
108 danger = self.calculate_danger_level()
109 return f"{base} | Drapieżnik | Niebezp.: {danger}/10"
110
111class Herbivore(Mammal):
112 """
113 Roślinożercy - dziedziczą z Mammal
114 """
115
116 def __init__(self, scientific_name, common_name, habitat, fur_color,
117 gestation_days, diet_type):
118 super().__init__(scientific_name, common_name, habitat, fur_color, gestation_days)
119 self.diet_type = diet_type # "liście", "trawa", "owoce"
120
121 def graze(self):
122 return f"{self.common_name} je {self.diet_type}"
123
124 def describe(self):
125 base = super().describe()
126 return f"{base} | Roślinożerca | Dieta: {self.diet_type}"
127
128class Feline(Carnivore):
129 """
130 Kotowate - dziedziczą z Carnivore
131 """
132
133 family = "Felidae"
134
135 def __init__(self, scientific_name, common_name, habitat, fur_color,
136 gestation_days, has_mane=False, pride_size=1):
137 super().__init__(
138 scientific_name, common_name, habitat, fur_color,
139 gestation_days, "zasadzka i pościg", pack_hunter=(pride_size > 1)
140 )
141 self.has_mane = has_mane
142 self.pride_size = pride_size
143
144 def retract_claws(self):
145 return f"{self.common_name} chowa ostre pazury"
146
147 def stalk_prey(self):
148 return f"{self.common_name} skrada się cicho do zdobyczy"
149
150 def describe(self):
151 base = super().describe()
152 social = f"stadne ({self.pride_size})" if self.pride_size > 1 else "samotne"
153 return f"{base} | Kotowate | {social}"
154
155class Canine(Carnivore):
156 """
157 Psowate - dziedziczą z Carnivore
158 """
159
160 family = "Canidae"
161
162 def __init__(self, scientific_name, common_name, habitat, fur_color,
163 gestation_days, pack_size=1):
164 super().__init__(
165 scientific_name, common_name, habitat, fur_color,
166 gestation_days, "pościg na dystansie", pack_hunter=(pack_size > 1)
167 )
168 self.pack_size = pack_size
169
170 def howl(self):
171 return f"{self.common_name} wyje do stada"
172
173 def track_scent(self):
174 return f"{self.common_name} tropi zdobycz po zapachu"
175
176 def describe(self):
177 base = super().describe()
178 social = f"wataha ({self.pack_size})" if self.pack_size > 1 else "samotne"
179 return f"{base} | Psowate | {social}"
180
181# === DEMONSTRACJA - Tworzenie hierarchii Safari ===
182
183print("=== KATALOG GATUNKÓW SAFARI - HIERARCHIA ===\n")
184
185# Kotowate
186lion = Feline(
187 scientific_name="Panthera leo",
188 common_name="Lew",
189 habitat="sawanna",
190 fur_color="złoty",
191 gestation_days=110,
192 has_mane=True,
193 pride_size=15
194)
195
196leopard = Feline(
197 scientific_name="Panthera pardus",
198 common_name="Lampart",
199 habitat="sawanna i lasy",
200 fur_color="żółty w czarne plamy",
201 gestation_days=90,
202 has_mane=False,
203 pride_size=1 # Samotnik
204)
205
206# Psowate
207wild_dog = Canine(
208 scientific_name="Lycaon pictus",
209 common_name="Likaon",
210 habitat="sawanna",
211 fur_color="pstrokaty",
212 gestation_days=70,
213 pack_size=20
214)
215
216# Roślinożercy
217elephant = Herbivore(
218 scientific_name="Loxodonta africana",
219 common_name="Słoń afrykański",
220 habitat="sawanna",
221 fur_color="szary",
222 gestation_days=645, # Najdłuższa ciąża!
223 diet_type="liście, kora, trawa"
224)
225
226giraffe = Herbivore(
227 scientific_name="Giraffa camelopardalis",
228 common_name="Żyrafa",
229 habitat="sawanna",
230 fur_color="żółty w brązowe plamy",
231 gestation_days=440,
232 diet_type="liście akacji"
233)
234
235# Ptaki
236eagle = Bird(
237 scientific_name="Aquila rapax",
238 common_name="Orzeł stepowy",
239 habitat="sawanna",
240 wingspan_m=2.1,
241 can_fly=True
242)
243
244# Dodaj obserwacje
245lion.add_observation("2024-01-15", "Serengeti", 12, "Stado polujące na gnu")
246lion.add_observation("2024-01-20", "Masai Mara", 8, "Rodzina z młodymi")
247leopard.add_observation("2024-01-16", "Obszar skalny", 1, "Samotny samiec")
248wild_dog.add_observation("2024-01-18", "Savuti", 18, "Wataha polująca")
249elephant.add_observation("2024-01-17", "Amboseli", 45, "Duże stado przy wodopoju")
250giraffe.add_observation("2024-01-19", "Tarangire", 23, "Żyją żyrafą akacjami")
251eagle.add_observation("2024-01-21", "Niebo nad sawanną", 3, "Para z młodym")
252
253# Wyświetl opisy - każdy używa swojej wersji describe()
254print("🦁 LEW:")
255print(f" {lion.describe()}")
256print(f" {lion.hunt()}")
257print(f" {lion.stalk_prey()}")
258print(f" {lion.retract_claws()}")
259print(f" {lion.nurse_young()}")
260print(f" Obserwacje: {lion.get_total_observed()} osobników")
261
262print(f"\n🐆 LAMPART:")
263print(f" {leopard.describe()}")
264print(f" {leopard.hunt()}")
265print(f" Poziom niebezpieczeństwa: {leopard.calculate_danger_level()}/10")
266
267print(f"\n🐺 LIKAON:")
268print(f" {wild_dog.describe()}")
269print(f" {wild_dog.hunt()}")
270print(f" {wild_dog.howl()}")
271print(f" {wild_dog.track_scent()}")
272
273print(f"\n🐘 SŁOŃ:")
274print(f" {elephant.describe()}")
275print(f" {elephant.graze()}")
276print(f" Obserwacje: {elephant.get_total_observed()} osobników")
277
278print(f"\n🦒 ŻYRAFA:")
279print(f" {giraffe.describe()}")
280print(f" {giraffe.graze()}")
281
282print(f"\n🦅 ORZEŁ:")
283print(f" {eagle.describe()}")
284print(f" {eagle.lay_eggs()}")
285
286# Sprawdź hierarchię
287print(f"\n=== HIERARCHIA KLAS ===")
288print(f"Lew dziedziczy z Feline? {isinstance(lion, Feline)}")
289print(f"Lew dziedziczy z Carnivore? {isinstance(lion, Carnivore)}")
290print(f"Lew dziedziczy z Mammal? {isinstance(lion, Mammal)}")
291print(f"Lew dziedziczy z Species? {isinstance(lion, Species)}")
292print(f"Lew dziedziczy z Bird? {isinstance(lion, Bird)}")
293
294print(f"\nMRO Feline: {[cls.__name__ for cls in Feline.mro()]}")
295# ['Feline', 'Carnivore', 'Mammal', 'Species', 'object']
296
297print(f"\n=== STATYSTYKI ===")
298print(f"Łączna liczba gatunków w katalogu: {Species.total_species_count}")
299
300# Polimorfizm - każdy gatunek ma swoją implementację describe()
301print(f"\nWszystkie gatunki:")
302all_animals = [lion, leopard, wild_dog, elephant, giraffe, eagle]
303for animal in all_animals:
304 print(f" - {animal.describe()}")✅ Użyj dziedziczenia gdy:
❌ NIE używaj dziedziczenia gdy:
1# ✅ Dobre - relacja "jest"
2class Animal:
3 pass
4
5class Dog(Animal): # Pies JEST zwierzęciem
6 pass
7
8# ❌ Złe - relacja "ma"
9class Engine:
10 def start(self):
11 return "Silnik uruchomiony"
12
13class Car(Engine): # NIE! Samochód NIE JEST silnikiem!
14 pass
15
16# ✅ Dobre - kompozycja
17class Car:
18 def __init__(self):
19 self.engine = Engine() # Samochód MA silnik
20
21 def start(self):
22 return self.engine.start()Obiekt klasy pochodnej powinien móc zastąpić obiekt klasy bazowej bez zmiany poprawności programu.
1def make_sound(animal):
2 """Funkcja przyjmuje dowolne Animal"""
3 print(animal.speak())
4
5class Animal:
6 def speak(self):
7 return "..."
8
9class Dog(Animal):
10 def speak(self):
11 return "Hau!"
12
13class Cat(Animal):
14 def speak(self):
15 return "Miau!"
16
17# LSP - Dog i Cat mogą zastąpić Animal
18make_sound(Dog()) # "Hau!" - działa
19make_sound(Cat()) # "Miau!" - działa1# ❌ Złe - zbyt głęboka hierarchia
2class A:
3 pass
4class B(A):
5 pass
6class C(B):
7 pass
8class D(C):
9 pass
10class E(D):
11 pass
12class F(E): # 6 poziomów!
13 pass
14
15# ✅ Dobre - płaska, zrozumiała hierarchia
16class Animal:
17 pass
18
19class Mammal(Animal):
20 pass
21
22class Lion(Mammal):
23 pass
24# 3 poziomy - czytelne!W tej lekcji nauczyłeś/aś się:
class Child(Parent)super() do wywołania metod rodzicaisinstance() i issubclass()Przed przejściem dalej:
super() w konstruktorzeAnalogia Safari: Hierarchia klas to drzewo ewolucyjne - każdy potomek dziedziczy cechy przodków, ale rozwija własne unikalne adaptacje! 🌳🦁🐘
W następnej lekcji Darwin nauczy Cię enkapsulacji - jak chronić wrażliwe dane gatunków przed nieautoryzowanym dostępem! 🔒📊