Odcinek 9/15 – Programowanie obiektowe (OOP) w Pythonie

foto kurs pythona odcinek 9

Cel: po tym rozdziale:

  • będziesz wiedzieć, czym są klasy i obiekty,
  • napiszesz własne klasy z metodami,
  • poznasz dziedziczenie i podstawy dobrych praktyk.

1) Klasa i obiekt – co to w ogóle jest?

  • Klasaprzepis na rzecz w programie (np. samochód, konto w banku).
  • Obiektkonkretny egzemplarz tego przepisu.

Wyobraź sobie przepis na pizzę (klasa) i pizzę na talerzu (obiekt).


2) Tworzenie klasy i obiektu – pierwszy przykład

class Samochod:
    def __init__(self, marka, model):
        self.marka = marka
        self.model = model

    def info(self):
        print(f"Samochód: {self.marka} {self.model}")

auto = Samochod("Toyota", "Corolla")
auto.info()   # Samochód: Toyota Corolla
  • class – tworzy klasę.
  • __init__konstruktor, uruchamia się przy tworzeniu obiektu.
  • self – zawsze oznacza ten konkretny obiekt.

3) Atrybuty: wspólne i indywidualne

class Kot:
    gatunek = "kot domowy"   # wspólne dla wszystkich kotów

    def __init__(self, imie):
        self.imie = imie     # indywidualne dla każdego kota

k1 = Kot("Mruczek")
k2 = Kot("Puszek")

print(k1.gatunek, k1.imie)  # kot domowy Mruczek
print(k2.gatunek, k2.imie)  # kot domowy Puszek
  • Atrybut klasy – taki sam dla wszystkich (gatunek).
  • Atrybut instancji – własny dla każdego obiektu (imie).

4) Metody: instancji, klasy i statyczne

class Licznik:
    liczba_obiektow = 0

    def __init__(self):
        Licznik.liczba_obiektow += 1

    @classmethod
    def ile(cls):
        print("Utworzono obiektów:", cls.liczba_obiektow)

    @staticmethod
    def opis():
        print("To jest zwykły licznik.")
  • Metoda instancji – ma self, działa na jednym obiekcie.
  • Metoda klasy – ma cls, działa na całej klasie.
  • Metoda statyczna – zwykła funkcja „schowana” w klasie.

5) Dziedziczenie – dzieci przejmują cechy rodziców

Dzięki dziedziczeniu możesz tworzyć nowe klasy na podstawie istniejących.

class Zwierze:
    def dzwiek(self):
        print("Nieznany dźwięk")

class Pies(Zwierze):
    def dzwiek(self):
        print("Hau hau!")

class Kot(Zwierze):
    def dzwiek(self):
        print("Miau!")

p = Pies()
p.dzwiek()  # Hau hau!

Nowa klasa (Pies) dziedziczy wszystko z klasy Zwierze, a dodatkowo zmienia potrzebne elementy.


6) Metody specjalne („dunder methods”)

To metody, które zaczynają się i kończą podwójnym podkreślnikiem, np. __init__.
Najczęściej używane:

  • __init__ – konstruktor,
  • __str__ – opis obiektu w print(),
  • __len__, __eq__ – np. długość i porównanie.

Przykład:

class Osoba:
    def __init__(self, imie, wiek):
        self.imie = imie
        self.wiek = wiek

    def __str__(self):
        return f"{self.imie} ({self.wiek} lat)"

o = Osoba("Ala", 21)
print(o)   # Ala (21 lat)

7) Kapsułkowanie – ukrywanie danych

W Pythonie nie ma pełnej prywatności, ale są konwencje:

  • _zmienna – umówiony znak: „to do użytku wewnętrznego”.
  • __zmienna – Python utrudnia bezpośredni dostęp (tzw. name mangling).
class Konto:
    def __init__(self, saldo=0):
        self.__saldo = saldo

    def wplata(self, kwota):
        self.__saldo += kwota

    def saldo(self):
        return self.__saldo

8) Praktyczne przykłady

A) Klasa BankAccount

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        self.balance += amount

    def withdraw(self, amount):
        if amount <= self.balance:
            self.balance -= amount
        else:
            print("Brak środków!")

    def __str__(self):
        return f"Konto {self.owner}, saldo: {self.balance} zł"

acc = BankAccount("Paweł", 100)
acc.deposit(50)
acc.withdraw(120)
print(acc)

B) Prosta gra RPG – postać

class Postac:
    def __init__(self, name, hp):
        self.name = name
        self.hp = hp

    def attack(self, other):
        other.hp -= 10
        print(f"{self.name} atakuje {other.name}! HP {other.name}: {other.hp}")

hero = Postac("Wojownik", 100)
enemy = Postac("Goblin", 50)

hero.attack(enemy)

9) Typowe pułapki

  • Brak self w metodziedef metoda(): ❌ zamiast def metoda(self):
  • Zmienna klasy zamiast instancji – wszystkie obiekty dzielą wtedy tę samą wartość.
  • Nadpisywanie metod bez super() – przy dziedziczeniu może „zgubić” kod rodzica.

10) Zadania do samodzielnego zrobienia

  1. Student – imię, rok, lista ocen. Metody: dodaj ocenę, policz średnią.
  2. Prostokąt – oblicz pole i obwód.
  3. Biblioteka – lista książek (napisy). Dodawanie, usuwanie, wyświetlanie.
  4. Samolot – metody start i lądowanie. Dziedziczenie: SamolotPasazerski z atrybutem liczba_miejsc.
  5. Sklep – słownik produktów i cen. Metoda kup zmniejsza stan i liczy koszt.

Co zabierasz z odcinka 9?

  • Wiesz, jak tworzyć klasy i obiekty.
  • Umiesz używać konstruktora __init__ i metod specjalnych.
  • Rozumiesz dziedziczenie i umiesz je zastosować.
  • Znasz podstawy kapsułkowania i unikasz typowych błędów.
  • Potrafisz wykorzystać OOP w praktycznych mini-projektach.