Spis zadań w tym module

  1. Modelowanie profilu studenta (Inicjalizacja stanu)
  2. Symulator pojazdu (Interakcja z metodami)
  3. System obsługi konta bankowego (Logika biznesowa)
  4. Katalog produktów z automatyczną wyceną (Wartości domyślne)
  5. Wirtualne zwierzątko (Zarządzanie wieloma stanami)

1. Dlaczego programowanie obiektowe?

W tradycyjnym podejściu proceduralnym kod opiera się na funkcjach przetwarzających luźne dane. W OOP (Object-Oriented Programming) łączymy dane (atrybuty) oraz operacje na nich (metody) w jedną, spójną całość zwaną obiektem. Pozwala to na lepszą organizację kodu, łatwiejszą rozbudowę systemów oraz modelowanie rzeczywistości w sposób intuicyjny.

2. Klasa vs Obiekt

Klasa to projekt, schemat lub "przepis", według którego tworzymy konkretne byty. Obiekt (instancja) to konkretny egzemplarz stworzony na podstawie tej klasy. Na przykład klasa Samochod to ogólny opis tego, co samochód posiada, a obiekt to konkretna Toyota stojąca przed Twoim domem.

01
Modelowanie profilu studenta (Inicjalizacja stanu)
Czego student się nauczy

Definiowania klas, używania specjalnej metody __init__, przypisywania atrybutów do instancji za pomocą self oraz tworzenia wielu obiektów tej samej klasy.

Scenariusz

Wyobraź sobie, że zostałeś zatrudniony jako programista w dziale IT nowoczesnej uczelni wyższej, która właśnie wdraża nowy system elektronicznej ewidencji akademickiej. Pierwszym i najważniejszym krokiem w tym procesie jest stworzenie precyzyjnej, cyfrowej reprezentacji każdego studenta, która stanie się fundamentem dla wszystkich przyszłych operacji administracyjnych. Każdy profil w bazie danych musi w sposób ujednolicony przechowywać kluczowe informacje, takie jak imię, nazwisko oraz unikalny numer indeksu przypisany do konkretnej osoby. Twoim zadaniem jest zaprojektowanie klasy, która nie tylko pozwoli na bezpieczne składowanie tych danych, ale również umożliwi ich błyskawiczne wyświetlenie w czytelnej formie. Dzięki takiemu podejściu, dziekanat będzie mógł sprawnie zarządzać listami studentów, unikając błędów wynikających z nieuporządkowanego przechowywania informacji w luźnych plikach. Gotowa klasa powinna działać jako uniwersalny wzorzec, pozwalający na tworzenie tysięcy indywidualnych instancji odpowiadających rzeczywistym osobom studiującym na uczelni. To zadanie wprowadzi Cię w świat modelowania obiektowego, gdzie każda rzecz z rzeczywistości znajduje swoje precyzyjne odzwierciedlenie w kodzie programu.

Wymagania techniczne
  • Zdefiniuj klasę o nazwie Student zgodnie z konwencją PascalCase.
  • Zaimplementuj konstruktor __init__ przyjmujący parametry: imię, nazwisko oraz numer indeksu.
  • Przypisz otrzymane wartości do atrybutów instancji przy użyciu słowa kluczowego self.
  • Stwórz metodę wyswietl_dane() prezentującą profil studenta w sformatowanym ciągu znaków.
  • Upewnij się, że metoda wyświetla dane w formacie: "Student: [Imię] [Nazwisko], Indeks: [Numer]".
  • Utwórz co najmniej dwie niezależne instancje klasy reprezentujące różnych studentów.
  • Wywołaj metodę prezentacyjną dla każdego z utworzonych obiektów osobno.
  • Sprawdź poprawność przechowywania danych poprzez weryfikację wypisanych informacji w konsoli.
Wskazówki wykonania
  • Rozpocznij od słowa kluczowego class, po którym następuje nazwa Student.
  • Pamiętaj, aby nazwa klasy była napisana wielką literą, zgodnie z konwencją PascalCase.
  • Zdefiniuj metodę __init__(self, imie, nazwisko, indeks), która służy do inicjalizacji obiektu.
  • Wewnątrz konstruktora użyj self.imie = imie, aby przypisać wartość do instancji.
  • Metoda wyswietl_dane(self) musi przyjmować self jako pierwszy argument.
  • Do łączenia tekstów i zmiennych w metodzie wyświetlającej użyj f-stringów, np. f"Student: {self.imie}".
  • Obiekty twórz poprzez wywołanie nazwy klasy z argumentami: s = Student("Jan", "Kowalski", "123").
  • Wywołuj metody na konkretnych obiektach, używając kropki: s.wyswietl_dane().
  • Pamiętaj, że każdy utworzony student ma własną, niezależną kopię atrybutów w pamięci.
  • Sprawdź, czy nie pomyliłeś self z nazwą klasy wewnątrz metod.
Przykładowy ekran
>>> s1 = Student("Adam", "Nowak", "12345") >>> s2 = Student("Ewa", "Kowalska", "67890") >>> s1.wyswietl_dane() Student: Adam Nowak, Indeks: 12345 >>> s2.wyswietl_dane() Student: Ewa Kowalska, Indeks: 67890
Wnioski do opracowania
  • Wyjaśnij rolę słowa kluczowego self jako unikalnego wskaźnika na konkretną instancję obiektu w pamięci.
  • Opisz, dlaczego konstruktor __init__ jest nazywany metodą magiczną i w którym momencie cyklu życia obiektu się uruchamia.
  • Przeanalizuj proces tworzenia wielu obiektów tej samej klasy – w jaki sposób Python izoluje ich dane od siebie?
  • Zastanów się i opisz skutki pominięcia self przed nazwą atrybutu wewnątrz metod klasy.
  • Omów znaczenie stosowania konwencji PascalCase dla nazw klas w kontekście czytelności i standardów PEP 8.
  • Porównaj składnię wywoływania metod z użyciem kropki (np. s1.wyswietl()) do wywoływania tradycyjnych funkcji.
  • Udowodnij na przykładzie, że zmiana wartości atrybutu w jednym obiekcie nie wpływa na stan innych instancji tej samej klasy.
  • Opisz różnicę między atrybutem instancji inicjalizowanym w __init__ a statycznymi danymi klasy.
  • Wnioskuj o przydatności f-stringów w budowaniu dynamicznych i czytelnych komunikatów prezentujących stan obiektu.
Zadanie 1

Rozwiązanie

3. Konstruktor __init__ i słowo self

Metoda __init__ jest wywoływana automatycznie w momencie tworzenia obiektu. To idealne miejsce na nadanie obiektowi jego początkowych cech (stanu). self to referencja do konkretnego obiektu, nad którym aktualnie pracujemy – pozwala on klasie "wiedzieć", o czyje dane chodzi.

02
Symulator pojazdu (Interakcja z metodami)
Czego student się nauczy

Modyfikowania stanu obiektu za pomocą metod, obsługi atrybutów liczbowych oraz implementacji prostej logiki zmiany wartości wewnątrz klasy.

Scenariusz

Rozpoczynasz prace nad autorskim silnikiem do nowej, ambitnej gry wyścigowej, która stawia na realizm w zarządzaniu parametrami technicznymi maszyn. Każdy nowo zakupiony w grze samochód opuszcza wirtualny salon z idealnie czystą historią i zerowym przebiegiem na liczniku. Twoim kluczowym zadaniem jest zaimplementowanie inteligentnego mechanizmu, który będzie wiernie odwzorowywał proces eksploatacji pojazdu podczas każdego wyścigu czy treningu. Musisz stworzyć metodę pozwalającą na symulację jazdy, która w sposób bezpieczny i kontrolowany zaktualizuje całkowity dystans pokonany przez dany samochód. Ważnym elementem projektu jest zapewnienie spójności danych, co oznacza, że system musi kategorycznie blokować próby wprowadzenia nielogicznych, ujemnych wartości przebiegu. Dzięki takiemu rozwiązaniu, gracze będą mogli śledzić historię swoich postępów i dbać o kondycję techniczną swojej floty w miarę upływu czasu w grze. Tak zaprojektowana klasa pojazdu stanie się sercem Twojego symulatora, umożliwiając dalszą rozbudowę o systemy zużycia paliwa czy konieczność przeprowadzania przeglądów. Gotowy moduł pokaże Ci, jak efektywnie zarządzać zmieniającym się stanem obiektu w dynamicznym środowisku aplikacji.

Wymagania techniczne
  • Utwórz klasę Samochod z atrybutami instancji: marka, model oraz przebieg.
  • Zainicjalizuj atrybut przebieg wartością domyślną równą 0 wewnątrz konstruktora.
  • Zaimplementuj metodę jedz(dystans) odpowiedzialną za zwiększanie stanu licznika pojazdu.
  • Dodaj mechanizm walidacji sprawdzający, czy przekazany dystans jest wartością dodatnią.
  • Wyświetl stosowny komunikat błędu w przypadku próby wprowadzenia ujemnego dystansu.
  • Stwórz metodę pokaz_przebieg() zwracającą czytelną informację o aktualnym stanie licznika.
  • Przetestuj działanie metody jedz() poprzez kilkukrotne dodawanie różnych dystansów.
  • Zweryfikuj końcowy przebieg, wywołując metodę prezentacyjną po serii wirtualnych podróży.
Wskazówki wykonania
  • Zdefiniuj klasę Samochod z trzema parametrami w metodzie __init__.
  • Atrybutowi self.przebieg nadaj wartość 0 bezpośrednio w konstruktorze, bez pobierania go z argumentu.
  • Metoda jedz(self, dystans) powinna najpierw sprawdzać warunek poprawności danych.
  • Użyj instrukcji if dystans > 0:, aby upewnić się, że przebieg nie zmaleje.
  • Jeśli warunek jest spełniony, zaktualizuj stan za pomocą self.przebieg += dystans.
  • W bloku else: wyświetl komunikat o błędzie za pomocą funkcji print().
  • Metoda pokaz_przebieg(self) powinna drukować sformatowany tekst z marką i modelem.
  • Przy testowaniu utwórz obiekt, np. moje_auto = Samochod("Ford", "Focus").
  • Wywołaj moje_auto.jedz(50) kilkukrotnie, aby sprawdzić, czy licznik poprawnie sumuje kilometry.
  • Spróbuj celowo podać -100 jako dystans, aby zweryfikować działanie Twojej walidacji.
Przykładowy ekran
>>> auto = Samochod("Toyota", "Corolla") >>> auto.jedz(150) >>> auto.jedz(50) >>> auto.pokaz_przebieg() Pojazd Toyota Corolla ma 200 km przebiegu. >>> auto.jedz(-10) Błąd: Dystans nie może być ujemny!
Wnioski do opracowania
  • Wyjaśnij pojęcie "stanu obiektu" na przykładzie dynamicznie zmieniającego się atrybutu self.przebieg.
  • Omów zalety stosowania walidacji danych wejściowych wewnątrz metod klasy jako skutecznego mechanizmu obronnego programu.
  • Przeanalizuj zagrożenia wynikające z bezpośredniego modyfikowania pól (np. auto.przebieg = -500) zamiast użycia metody.
  • Opisz, w jaki sposób metoda jedz() modeluje rzeczywiste zachowanie obiektu fizycznego w czasie rzeczywistym.
  • Zaproponuj, jak rozbudować klasę o dodatkową weryfikację stanu paliwa przed każdą zaplanowaną trasą podróży.
  • Wnioskuj o znaczeniu komunikatów diagnostycznych print() w informowaniu użytkownika o błędnej próbie zmiany stanu.
  • Omów czytelność kodu w sytuacji, gdy cała logika modyfikacji danych jest zamknięta wewnątrz klasy (hermetyzacja).
  • Porównaj operację inkrementacji (+=) do całkowitego nadpisywania wartości atrybutu nową liczbą.
  • Sprawdź i opisz zachowanie Twojego programu przy podaniu wartości granicznej (zero) jako dystansu podróży.
Zadanie 2

Rozwiązanie

4. Metody jako zachowania

Metody to funkcje zdefiniowane wewnątrz klasy. Definiują one akcje, jakie obiekt może wykonać. Metody mogą nie tylko wyświetlać dane, ale przede wszystkim zmieniać stan obiektu w sposób kontrolowany.

03
System obsługi konta bankowego (Logika biznesowa)
Czego student się nauczy

Łączenia wielu metod w celu realizacji złożonego scenariusza, pracy z atrybutami finansowymi oraz zabezpieczania stanu obiektu przed błędnymi operacjami (np. debetem).

Scenariusz

Zostałeś wybrany do stworzenia rdzenia nowoczesnego systemu bankowości elektronicznej dla nowo powstałego fintechu, który stawia na najwyższą jakość obsługi klienta. Fundamentem bezpieczeństwa finansowego każdego użytkownika jest precyzyjnie zaprojektowane konto, które musi nienagannie zarządzać saldem początkowym i każdą kolejną operacją. Twoim zadaniem jest zaimplementowanie zestawu bezpiecznych metod, które umożliwią klientom sprawne wpłacanie oszczędności oraz ich wypłacanie w dowolnym momencie. System musi być wyposażony w rygorystyczne mechanizmy walidacji, które kategorycznie uniemożliwią powstanie niedozwolonego debetu na rachunku użytkownika. Każda próba wypłaty kwoty przewyższającej aktualnie dostępne środki powinna zostać natychmiast zablokowana i opatrzona stosownym komunikatem ostrzegawczym. Dzięki takiemu podejściu, integralność danych finansowych w Twojej aplikacji pozostanie nienaruszona, budując zaufanie wśród przyszłych klientów banku. Takie modelowanie procesów biznesowych uczy, jak za pomocą metod klasy chronić wrażliwe zasoby przed błędnymi lub nieautoryzowanymi zmianami stanu. Gotowe rozwiązanie będzie stanowiło wzorcowy przykład profesjonalnego zarządzania logiką transakcyjną w środowisku obiektowym.

Wymagania techniczne
  • Zdefiniuj klasę KontoBankowe z atrybutami wlasciciel (tekst) oraz saldo (liczba).
  • Pozwól na ustawienie początkowego stanu konta podczas tworzenia obiektu w konstruktorze.
  • Zaimplementuj metodę wplata(kwota) do bezpiecznego zwiększania dostępnych środków.
  • Opracuj metodę wyplata(kwota) realizującą proces pobierania pieniędzy z rachunku.
  • Wprowadź blokadę wypłaty w sytuacji, gdy żądana kwota przewyższa aktualne saldo konta.
  • Wyświetl czytelny komunikat o braku środków lub powodzeniu operacji po każdej próbie wypłaty.
  • Stwórz metodę sprawdz_saldo() do szybkiego podglądu aktualnego stanu finansowego.
  • Przeprowadź symulację serii wpłat i wypłat, w tym próbę wypłaty kwoty większej niż saldo.
Wskazówki wykonania
  • Klasa KontoBankowe powinna w konstruktorze przyjmować wlasciciel oraz saldo_poczatkowe.
  • Przypisz saldo do atrybutu self.saldo, który będzie modyfikowany przez inne metody.
  • Metoda wplata(self, kwota) powinna zwiększać self.saldo o podaną wartość.
  • W metodzie wyplata(self, kwota) dodaj kluczowy warunek logiczny if kwota <= self.saldo:.
  • Jeśli kwota jest mniejsza lub równa saldu, odejmij ją: self.saldo -= kwota.
  • W przypadku braku środków poinformuj użytkownika, nie zmieniając stanu konta za pomocą print().
  • Użyj f-stringów, aby w komunikatach pokazywać aktualny stan konta po operacji.
  • Metoda sprawdz_saldo(self) może być prostym wywołaniem print(f"Saldo: {self.saldo}").
  • Przetestuj scenariusz brzegowy – próba wypłaty dokładnie takiej kwoty, jaka jest na koncie.
  • Pamiętaj o obsłudze sytuacji, w której ktoś próbuje wpłacić lub wypłacić ujemną kwotę.
Przykładowy ekran
>>> moje_konto = KontoBankowe("Jan Kowalski", 1000) >>> moje_konto.wplata(500) >>> moje_konto.wyplata(2000) Błąd: Niewystarczające środki. >>> moje_konto.wyplata(300) Operacja pomyślna. Saldo: 1200
Wnioski do opracowania
  • Przeanalizuj kluczową rolę instrukcji warunkowych w zabezpieczaniu krytycznej logiki biznesowej transakcji bankowych.
  • Opisz, w jaki sposób warunek if kwota <= self.saldo skutecznie zapobiega powstawaniu błędów finansowych.
  • Omów znaczenie natychmiastowej aktualizacji stanu obiektu "na żywo" po każdej pomyślnie zrealizowanej operacji.
  • Zastanów się i opisz, jak system powinien zareagować na próbę wpłaty kwoty ujemnej za pomocą metody wplata().
  • Wnioskuj o poziomie bezpieczeństwa danych w systemie, który nie stosuje prywatnych pól (atrybutów z podkreśleniem).
  • Porównaj metody wplata i wyplata pod kątem ich wpływu na spójność danych finansowych w pamięci.
  • Opisz, jak wyświetlanie aktualnego salda po każdej operacji buduje poprawny interfejs komunikacji z użytkownikiem.
  • Sprawdź, czy po serii nieudanych prób wypłaty stan konta (atrybut saldo) pozostaje całkowicie nienaruszony.
  • Omów elastyczność wykorzystania parametrów konstruktora do inicjalizacji kont z różnymi poziomami środków startowych.
Zadanie 3

Rozwiązanie

5. Atrybuty i ich domyślne wartości

Nie wszystkie dane muszą być podawane przez użytkownika przy tworzeniu obiektu. Możemy zdefiniować wartości domyślne, co upraszcza tworzenie instancji w typowych przypadkach.

04
Katalog produktów z automatyczną wyceną (Wartości domyślne)
Czego student się nauczy

Wykorzystywania parametrów opcjonalnych w konstruktorze, obliczania wartości na podstawie atrybutów oraz formatowania wyników numerycznych.

Scenariusz

Jako właściciel dynamicznie rozwijającego się sklepu internetowego, stoisz przed wyzwaniem pełnej automatyzacji procesu wyceny oferowanego asortymentu. Ręczne przeliczanie podatków dla każdego z tysięcy produktów jest żmudne i podatne na kosztowne pomyłki, dlatego potrzebujesz niezawodnego narzędzia programistycznego. Twoim celem jest zaprojektowanie klasy produktu, która w inteligentny sposób zajmie się wyliczaniem ceny brutto na podstawie podanych wartości netto. System powinien być na tyle elastyczny, aby domyślnie stosować podstawową stawkę VAT wynoszącą dwadzieścia trzy procent, ale jednocześnie pozwalać na jej łatwą zmianę dla artykułów spożywczych czy leków. Musisz stworzyć mechanizm, który w dowolnym momencie wygeneruje pełną specyfikację towaru, prezentując wszystkie składowe ceny w sposób przejrzysty dla klienta. Dzięki zastosowaniu parametrów domyślnych w konstruktorze, tworzenie nowych wpisów do katalogu stanie się znacznie szybsze i mniej uciążliwe dla operatorów systemu. Takie rozwiązanie nie tylko usprawni Twoją codzienną pracę, ale również zapewni pełną zgodność z obowiązującymi przepisami podatkowymi w każdym kanale sprzedaży. Gotowy moduł wyceny będzie kluczowym elementem Twojej platformy e-commerce, gwarantującym poprawność obliczeń finansowych.

Wymagania techniczne
  • Zbuduj klasę Produkt przechowującą nazwę oraz cenę netto wybranego towaru.
  • Wykorzystaj parametr domyślny w konstruktorze dla stawki podatku VAT (ustaw na 0.23).
  • Zaimplementuj metodę pobierz_cene_brutto() wykonującą obliczenia matematyczne ceny z podatkiem.
  • Zastosuj wzór: cena_brutto = cena_netto * (1 + stawka_vat) wewnątrz metody obliczeniowej.
  • Stwórz metodę info() prezentującą kompletną specyfikację towaru w jednym komunikacie.
  • Przetestuj tworzenie produktu z domyślną stawką VAT (np. dla elektroniki).
  • Utwórz obiekt z własną stawką podatku (np. 0.05 dla produktów spożywczych).
  • Wyświetl sformatowane dane obu produktów, porównując ich ceny netto i brutto.
Wskazówki wykonania
  • W definicji __init__ użyj zapisu def __init__(self, nazwa, cena_netto, vat=0.23):.
  • Dzięki vat=0.23, argument ten staje się opcjonalny przy tworzeniu obiektu.
  • Metoda pobierz_cene_brutto(self) powinna wykonywać działanie: return self.cena_netto * (1 + self.vat).
  • Pamiętaj, aby w obliczeniach używać self.vat, a nie twardo wpisanej liczby wewnątrz metody.
  • Metoda info(self) powinna wywołać self.pobierz_cene_brutto(), aby wyświetlić wynik końcowy.
  • Do wyświetlenia procentów w info() możesz użyć działania {self.vat * 100}%.
  • Przy tworzeniu p1 = Produkt("Laptop", 3000), Python sam podstawi 0.23 pod VAT.
  • Przy tworzeniu p2 = Produkt("Chleb", 4, 0.05), Twoja wartość 0.05 nadpisze domyślną.
  • Sprawdź, czy ceny brutto są poprawnie zaokrąglane (możesz użyć funkcji round(liczba, 2)).
  • Upewnij się, że atrybuty są poprawnie zainicjalizowane w pamięci obiektu przy użyciu self.
Przykładowy ekran
>>> p1 = Produkt("Laptop", 3000) >>> p2 = Produkt("Chleb", 4, 0.05) >>> print(p1.pobierz_cene_brutto()) 3690.0 >>> p2.info() Produkt: Chleb, Cena Netto: 4, VAT: 5%, Cena Brutto: 4.2
Wnioski do opracowania
  • Wyjaśnij, w jaki sposób stosowanie parametrów domyślnych (np. vat=0.23) znacząco skraca i upraszcza kod klienta.
  • Omów mechanizm nadpisywania wartości domyślnych przy tworzeniu specyficznych kategorii produktów (np. spożywczych).
  • Przeanalizuj zalety obliczania ceny brutto dynamicznie w metodzie zamiast przechowywania jej w stałym atrybucie.
  • Zastanów się, czy stawka podatkowa powinna być atrybutem konkretnej instancji czy raczej stałą zdefiniowaną na poziomie klasy.
  • Wnioskuj o znaczeniu precyzyjnych zaokrągleń za pomocą round() w profesjonalnych systemach sprzedażowych.
  • Opisz, jak metoda info() efektywnie deleguje zadania obliczeniowe do innych metod wewnątrz tej samej klasy.
  • Porównaj proces inicjalizacji produktu "standardowego" i "specjalnego" pod kątem liczby przekazywanych argumentów.
  • Omów korzyści z centralizacji logiki podatkowej – jak łatwo można zmienić stawkę VAT dla całego systemu w jednym miejscu.
  • Sprawdź poprawność działania algorytmu wyceny przy ustawieniu zerowej stawki podatku (produkty zwolnione z VAT).
Zadanie 4

Rozwiązanie

6. Zarządzanie stanem złożonym

Obiekty często posiadają wiele cech, które wzajemnie na siebie wpływają. Zrozumienie relacji między atrybutami jest kluczem do tworzenia zaawansowanych symulacji.

7. Modelowanie interakcji

W programowaniu obiektowym możemy projektować sytuacje, w których jedna akcja pociąga za sobą zmiany w kilku parametrach naraz, co idealnie oddaje procesy zachodzące w świecie rzeczywistym.

8. Dobre praktyki (PascalCase)

Zawsze pamiętaj o konwencjach nazewniczych. Klasy nazywamy WielkaLitera, a atrybuty i metody mala_litera_z_podkresleniem. To sprawia, że Twój kod jest profesjonalny i czytelny dla innych.

9. Modularność kodu

Dzięki klasom możesz łatwo przenosić gotowe "podzespoły" swojego programu do innych projektów. Raz dobrze zaprojektowana klasa KontoBankowe może służyć w wielu aplikacjach finansowych.

10. Podsumowanie Wstępu

W tym module poznałeś fundamenty: klasy jako matryce, obiekty jako ich instancje, rolę __init__ oraz znaczenie self. Potrafisz już tworzyć obiekty, nadawać im cechy i definiować ich zachowania. W kolejnych częściach dowiesz się, jak te obiekty mogą ze sobą współpracować!

05
Wirtualne zwierzątko (Zarządzanie wieloma stanami)
Czego student się nauczy

Tworzenia klasy z wieloma zmiennymi stanami, implementacji metod wpływających na kilka atrybutów jednocześnie oraz budowania prostych systemów zależności (np. głód wpływa na energię).

Scenariusz

Zapewne pamiętasz kultowe, interaktywne breloczki Tamagotchi, które uczyły całe pokolenia odpowiedzialności za wirtualnych podopiecznych poprzez zabawę i opiekę. Twoim wyzwaniem jest odtworzenie tego legendarnego mechanizmu poprzez stworzenie zaawansowanej klasy reprezentującej cyfrowe zwierzątko o unikalnym imieniu. Każdy Twój podopieczny będzie charakteryzował się dynamicznie zmieniającymi się poziomami głodu oraz energii, które musisz utrzymać w bezpiecznym zakresie od zera do stu punktów. Musisz zaprojektować zestaw interakcji, takich jak wspólna zabawa, która poprawi nastrój zwierzątka, ale jednocześnie spowoduje u niego naturalne zmęczenie i wzrost apetytu. Kluczowym elementem zadania jest stworzenie logicznych powiązań między atrybutami, gdzie jedna akcja pociąga za sobą zmiany w kilku parametrach życiowych jednocześnie. Twoja klasa musi również posiadać inteligentny system walidacji, który nie pozwoli, aby zwierzątko było "bardziej niż najedzone" lub miało ujemną energię. Dzięki takiemu podejściu do zarządzania stanem złożonym, nauczysz się projektować systemy o wysokim stopniu współzależności danych, co jest niezbędne w profesjonalnym tworzeniu gier. Gotowy projekt wirtualnego przyjaciela będzie doskonałym sprawdzianem Twoich umiejętności w zakresie modelowania zachowań i reakcji obiektów.

Wymagania techniczne
  • Zdefiniuj klasę Zwierze przyjmującą imię podopiecznego w momencie inicjalizacji.
  • Dodaj atrybuty instancji glod oraz energia, ustawiając ich stan początkowy (np. na 0 i 100).
  • Zaimplementuj metodę baw_sie() symulującą aktywność zwiększającą głód i zabierającą energię.
  • Opracuj metodę karm() pozwalającą na redukcję poziomu głodu zwierzątka.
  • Wprowadź mechanizm ograniczania wartości atrybutów do sztywnego zakresu od 0 do 100 punktów.
  • Wykorzystaj funkcje min() i max() do eleganckiego zabezpieczenia stanów przed przekroczeniem limitów.
  • Stwórz metodę status() generującą raport o aktualnej kondycji życiowej Twojego pupila.
  • Przetestuj system zależności poprzez serię akcji, sprawdzając czy statystyki nie przyjmują ujemnych wartości.
Wskazówki wykonania
  • Klasa Zwierze powinna startować z self.glod = 0 i self.energia = 100 w konstruktorze.
  • W metodzie baw_sie(self) zwiększ głód o stałą wartość (np. 15) i zmniejsz energię (np. 20).
  • Aby utrzymać głód w ryzach, użyj self.glod = min(100, self.glod + 15).
  • Funkcja min(100, x) gwarantuje, że wartość nigdy nie przekroczy stu punktów.
  • W metodzie karm(self) analogicznie użyj self.glod = max(0, self.glod - 20).
  • Funkcja max(0, x) sprawi, że głód nigdy nie spadnie poniżej zera (brak ujemnego głodu).
  • Metoda status(self) powinna w jednej linii wypisać imię oraz oba parametry życiowe.
  • Możesz dodać warunki sprawdzające, czy zwierzątko nie jest zbyt zmęczone na zabawę (jeśli energia < 20).
  • Przetestuj działanie pustej energii – czy baw_sie() nie obniży jej poniżej zera.
  • Pamiętaj o używaniu self przy każdym dostępie do atrybutów energia i glod.
Przykładowy ekran
>>> pupil = Zwierze("Burek") >>> pupil.baw_sie() >>> pupil.status() Zwierzę: Burek | Głód: 10 | Energia: 85 >>> pupil.karm() >>> pupil.status() Zwierzę: Burek | Głód: 0 | Energia: 85
Wnioski do opracowania
  • Wyjaśnij koncepcję współzależności wielu atrybutów (np. jak zabawa wpływa jednocześnie na głód i poziom energii).
  • Omów działanie funkcji min() i max() jako eleganckich i bezpiecznych ograniczników zakresu wartości (0-100).
  • Przeanalizuj logikę "blokady akcji" – co się stanie, gdy energia spadnie poniżej progu wymaganego do podjęcia zabawy?
  • Opisz, jak metoda status() agreguje rozproszone dane w jeden spójny i czytelny raport kondycji pupila.
  • Zaproponuj mechanizm "automatycznego starzenia się", który mógłby być wywoływany przy każdej interakcji z obiektem.
  • Wnioskuj o przewadze programowania obiektowego nad zmiennymi globalnymi przy modelowaniu skomplikowanych bytów.
  • Porównaj wpływ metod karm() i baw_sie() na ogólną szansę "przetrwania" wirtualnego zwierzątka.
  • Omów znaczenie unikalnej tożsamości (atrybut imie) nadawanej w konstruktorze dla rozróżniania wielu obiektów.
  • Sprawdź stabilność logiki po serii ekstremalnych akcji, np. wielokrotnym karmieniu już w pełni najedzonego zwierzęcia.
Zadanie 5

Rozwiązanie