Programowanie obiektowe w Pythonie
Programowanie obiektowe (OOP) to paradygmat programowania oparty na koncepcji obiektów, które zawierają dane i kod.
Klasy i obiekty:
Klasa to szablon do tworzenia obiektów. Obiekt to instancja klasy.
# Definiowanie klasy
class Dog:
def __init__(self, name, age, breed):
self.name = name # Atrybut instancji
self.age = age
self.breed = breed
def bark(self):
return f"{self.name} szczeka: Hau! Hau!"
def get_info(self):
return f"{self.name} to {self.breed} w wieku {self.age} lat"
def have_birthday(self):
self.age += 1
return f"{self.name} ma teraz {self.age} lat!"
# Tworzenie obiektów (instancji klasy)
my_dog = Dog("Burek", 3, "Owczarek niemiecki")
friend_dog = Dog("Luna", 2, "Golden Retriever")
# Używanie metod
print(my_dog.bark()) # Burek szczeka: Hau! Hau!
print(my_dog.get_info()) # Burek to Owczarek niemiecki w wieku 3 lat
print(my_dog.have_birthday()) # Burek ma teraz 4 lat!
print(friend_dog.get_info()) # Luna to Golden Retriever w wieku 2 latKonstruktor __init__:
Konstruktor jest wywoływany automatycznie przy tworzeniu obiektu.
class Person:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
self.friends = [] # Lista przyjaciół
def add_friend(self, friend):
self.friends.append(friend)
return f"{friend} został dodany do przyjaciół {self.name}"
def get_friends_count(self):
return len(self.friends)
def introduce(self):
return f"Cześć! Jestem {self.name}, mam {self.age} lat i mieszkam w {self.city}"
# Tworzenie osób
person1 = Person("Jan", 25, "Warszawa")
person2 = Person("Anna", 28, "Kraków")
print(person1.introduce()) # Cześć! Jestem Jan, mam 25 lat i mieszkam w Warszawie
person1.add_friend("Anna")
print(person1.get_friends_count()) # 1Atrybuty klasowe vs instancji:
class BankAccount:
# Atrybut klasowy - wspólny dla wszystkich instancji
bank_name = "Python Bank"
interest_rate = 0.05
def __init__(self, owner, balance=0):
# Atrybuty instancji - unikalne dla każdego obiektu
self.owner = owner
self.balance = balance
self.account_number = self._generate_account_number()
def _generate_account_number(self):
# Metoda prywatna (z podkreśleniem)
import random
return f"PL{random.randint(100000, 999999)}"
def deposit(self, amount):
if amount > 0:
self.balance += amount
return f"Wpłacono {amount} zł. Nowe saldo: {self.balance} zł"
else:
return "Kwota musi być większa od 0"
def withdraw(self, amount):
if amount <= self.balance:
self.balance -= amount
return f"Wypłacono {amount} zł. Nowe saldo: {self.balance} zł"
else:
return "Niewystarczające środki"
def get_interest(self):
interest = self.balance * self.interest_rate
return f"Oprocentowanie: {interest} zł"
# Tworzenie kont
account1 = BankAccount("Jan Kowalski", 1000)
account2 = BankAccount("Anna Nowak", 500)
print(account1.deposit(500)) # Wpłacono 500 zł. Nowe saldo: 1500 zł
print(account1.withdraw(200)) # Wypłacono 200 zł. Nowe saldo: 1300 zł
print(account1.get_interest()) # Oprocentowanie: 65.0 zł
# Dostęp do atrybutów klasowych
print(BankAccount.bank_name) # Python Bank
print(account1.bank_name) # Python Bank (można też przez instancję)Dziedziczenie:
Dziedziczenie pozwala na tworzenie nowych klas na podstawie istniejących.
# Klasa bazowa (rodzic)
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def make_sound(self):
return "Jakiś dźwięk"
def get_info(self):
return f"{self.name} to {self.species}"
# Klasa pochodna (dziecko)
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name, "pies") # Wywołanie konstruktora rodzica
self.breed = breed
def make_sound(self):
return "Hau! Hau!"
def fetch(self):
return f"{self.name} przynosi piłkę"
class Cat(Animal):
def __init__(self, name, color):
super().__init__(name, "kot")
self.color = color
def make_sound(self):
return "Miau! Miau!"
def climb(self):
return f"{self.name} wspina się na drzewo"
# Tworzenie obiektów
dog = Dog("Burek", "Owczarek")
cat = Cat("Mruczek", "Rudy")
print(dog.get_info()) # Burek to pies
print(dog.make_sound()) # Hau! Hau!
print(dog.fetch()) # Burek przynosi piłkę
print(cat.get_info()) # Mruczek to kot
print(cat.make_sound()) # Miau! Miau!
print(cat.climb()) # Mruczek wspina się na drzewoWielokrotne dziedziczenie:
class Flyable:
def fly(self):
return "Lecę w powietrzu!"
class Swimmable:
def swim(self):
return "Pływam w wodzie!"
class Duck(Animal, Flyable, Swimmable):
def __init__(self, name):
super().__init__(name, "kaczka")
def make_sound(self):
return "Kwa! Kwa!"
def quack_and_fly(self):
return f"{self.make_sound()} {self.fly()}"
duck = Duck("Kaczuszka")
print(duck.make_sound()) # Kwa! Kwa!
print(duck.fly()) # Lecę w powietrzu!
print(duck.swim()) # Pływam w wodzie!
print(duck.quack_and_fly()) # Kwa! Kwa! Lecę w powietrzu!Metody specjalne (magiczne):
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
def __str__(self):
return f"'{self.title}' autorstwa {self.author}"
def __repr__(self):
return f"Book('{self.title}', '{self.author}', {self.pages})"
def __len__(self):
return self.pages
def __add__(self, other):
if isinstance(other, Book):
return Book(f"{self.title} + {other.title}",
f"{self.author} + {other.author}",
self.pages + other.pages)
return "Nie można dodać książki do tego typu obiektu"
def __eq__(self, other):
if isinstance(other, Book):
return (self.title == other.title and
self.author == other.author and
self.pages == other.pages)
return False
book1 = Book("Python dla początkujących", "Jan Kowalski", 300)
book2 = Book("Zaawansowany Python", "Anna Nowak", 400)
print(str(book1)) # 'Python dla początkujących' autorstwa Jan Kowalski
print(repr(book1)) # Book('Python dla początkujących', 'Jan Kowalski', 300)
print(len(book1)) # 300
print(book1 + book2) # Book('Python dla początkujących + Zaawansowany Python', 'Jan Kowalski + Anna Nowak', 700)
print(book1 == book2) # FalseWłaściwości (Properties):
class Circle:
def __init__(self, radius):
self._radius = radius # Atrybut prywatny
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Promień nie może być ujemny")
self._radius = value
@property
def area(self):
import math
return math.pi * self._radius ** 2
@property
def circumference(self):
import math
return 2 * math.pi * self._radius
circle = Circle(5)
print(f"Promień: {circle.radius}") # Promień: 5
print(f"Pole: {circle.area:.2f}") # Pole: 78.54
print(f"Obwód: {circle.circumference:.2f}") # Obwód: 31.42
circle.radius = 10 # Ustawienie nowego promienia
print(f"Nowe pole: {circle.area:.2f}") # Nowe pole: 314.16
# circle.radius = -5 # Błąd: Promień nie może być ujemnyDobre praktyki OOP:
- Używaj opisowych nazw klas i metod
- Zachowaj enkapsulację (ukryj szczegóły implementacji)
- Używaj dziedziczenia do modelowania relacji „jest”
- Preferuj kompozycję nad dziedziczeniem
- Dokumentuj swoje klasy i metody
- Używaj właściwości zamiast getterów/setterów
- Implementuj metody specjalne gdy potrzeba
Ćwiczenie:
Stwórz klasę Student z atrybutami (imię, nazwisko, oceny) i metodami (dodaj ocenę, oblicz średnią, wyświetl informacje).
Brak odpowiedzi