Ten przewodnik obejmuje programowanie obiektowe (OOP) w Pythonie oraz menedżery kontekstowe, w tym praktyczne przykłady przechwytywania stdout/stderr oraz użycie wzorca Tee do jednoczesnego wyświetlania i zapisywania wyjścia.
In Questo Articolo
1. Klasy w Python
Klasy są centralnym mechanizmem OOP. Klasa to szablon do tworzenia obiektów z atrybutami (dane) i metodami (funkcje). Obiekty stworzone na podstawie klasy nazywane są instancjami. Klasy pomagają w strukturze kodu, zwiększają możliwość ponownego użycia i ułatwiają jego utrzymanie.
Struktura klasy
class ClassName:
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
def method(self):
return f'{self.param1} i {self.param2}'
Kluczowe punkty:
__init__: konstruktor do inicjalizacji atrybutów obiektu.self: odniesienie do bieżącej instancji.- Atrybuty: definiowane przez
selfi dostępne we wszystkich metodach. - Metody: działają na danych obiektu.
Tworzenie obiektów
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def description(self):
return f'{self.year} {self.make} {self.model}'
my_car = Car('Toyota', 'Corolla', 2020)
print(my_car.description()) # Wyjście: 2020 Toyota Corolla
Typy metod
- Metody instancji — działają na obiektach (
self). - Metody klasy — działają na klasie (
cls) przy użyciu@classmethod. - Metody statyczne — nie zależą ani od instancji, ani od klasy (
@staticmethod).
Dziedziczenie
class Animal:
def speak(self):
return 'Głos zwierzęcia'
class Dog(Animal):
def speak(self):
return 'Hau'
Polimorfizm
class Cat(Animal):
def speak(self):
return 'Miau'
cat = Cat()
print(cat.speak()) # Wyjście: Miau
- Ta sama nazwa metody może działać inaczej w zależności od typu obiektu.
Enkapsulacja
class Car:
def __init__(self, make, model):
self._make = make # chroniony atrybut
self._model = model
def get_make(self):
return self._make
def set_make(self, make):
self._make = make
Metody magiczne i destruktor
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'Point({self.x}, {self.y})'
p = Point(3, 4)
print(p) # Wyjście: Point(3, 4)
ASCII diagram: dziedziczenie i polimorfizm
┌─────────┐
│ Animal │
└─────────┘
│ speak() │
└─────────┘
▲
┌───────┴────────┐
│ │
┌─────────┐ ┌─────────┐
│ Dog │ │ Cat │
└─────────┘ └─────────┘
│ speak() │ │ speak() │
└─────────┘ └─────────┘
2. Menedżery kontekstowe w Python
Menedżery kontekstowe pozwalają automatycznie alokować i zwalniać zasoby, nawet w przypadku błędów.
Użycie @contextmanager
from contextlib import contextmanager
@contextmanager
def my_context():
print("Wejście do kontekstu")
try:
yield "Zasób"
finally:
print("Wyjście z kontekstu")
Użycie:
with my_context() as res:
print("W kontekście:", res)
Przechwytywanie stdout/stderr i Tee
Python pozwala przechwytywać stdout, stderr lub oba, a także jednocześnie wyświetlać i przechwytywać dzięki wzorcowi Tee.
3. Pełny przykład: oop_and_context.py
"""
oop_and_context.py
Przykłady klas, zasad OOP i menedżerów kontekstowych w Python.
Zawiera:
- Definicje klas, dziedziczenie, polimorfizm, enkapsulacja
- Metody instancji, klasy i statyczne
- Metody magiczne i destruktor
- Menedżery kontekstowe z @contextmanager
- Przechwytywanie stdout, stderr i obu jednocześnie
- Wzorzec Tee: wyświetlanie i przechwytywanie
- Menedżer kontekstowy oparty na klasie
"""
import sys
import io
from contextlib import contextmanager
# ==========================
# Część 1: Klasy i OOP
# ==========================
class Animal:
"""Bazowa klasa dla zwierząt."""
def speak(self):
return 'Głos zwierzęcia'
class Dog(Animal):
def speak(self):
return 'Hau'
class Cat(Animal):
def speak(self):
return 'Miau'
class Car:
"""Przykład enkapsulacji."""
def __init__(self, make, model, year=None):
self._make = make
self._model = model
self.year = year
def get_make(self):
return self._make
def set_make(self, make):
self._make = make
def description(self):
if self.year:
return f'{self.year} {self._make} {self._model}'
return f'{self._make} {self._model}'
class Point:
"""Klasa z metodami magicznymi."""
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'Point({self.x}, {self.y})'
# ==========================
# Część 2: Menedżery kontekstowe
# ==========================
@contextmanager
def my_context():
print("Wejście do kontekstu")
try:
yield "Zasób"
finally:
print("Wyjście z kontekstu")
@contextmanager
def capture_stdout():
old_stdout = sys.stdout
sys.stdout = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
@contextmanager
def capture_stderr():
old_stderr = sys.stderr
sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stderr = old_stderr
@contextmanager
def capture_output():
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
class Tee(io.StringIO):
"""Wyświetlanie i przechwytywanie jednocześnie."""
def __init__(self, original):
super().__init__()
self.original = original
def write(self, text):
self.original.write(text)
super().write(text)
def flush(self):
self.original.flush()
@contextmanager
def capture_stdout_tee():
old_stdout = sys.stdout
sys.stdout = tee = Tee(old_stdout)
try:
yield tee
finally:
sys.stdout = old_stdout
# ==========================
# Część 3: Menedżer kontekstowy oparty na klasie
# ==========================
class OutputCapture:
"""Menedżer kontekstowy do przechwytywania stdout."""
def __init__(self):
self._buffer = io.StringIO()
self._old_stdout = None
def __enter__(self):
self._old_stdout = sys.stdout
sys.stdout = self._buffer
return self._buffer
def __exit__(self, exc_type, exc_val, exc_tb):
sys.stdout = self._old_stdout
return False # przekazanie wyjątku dalej
# ==========================
# Część 4: Demonstracje
# ==========================
def demo_classes():
print("\n--- Demonstracja klas ---")
dog = Dog()
cat = Cat()
print("Pies mówi:", dog.speak())
print("Kot mówi:", cat.speak())
my_car = Car('Toyota', 'Corolla', 2020)
print("Opis auta:", my_car.description())
my_car.set_make('Honda')
print("Zaktualizowana marka:", my_car.get_make())
point = Point(3, 4)
print("Punkt:", point)
def demo_context_managers():
print("\n--- Demonstracja menedżerów kontekstowych ---")
with my_context() as res:
print("W kontekście:", res)
with capture_stdout() as out:
print("stdout przechwycone")
print("Bufor:", out.getvalue().strip())
with capture_stderr() as err:
print("Idzie do stdout")
sys.stderr.write("Komunikat o błędzie\n")
print("Błąd:", err.getvalue().strip())
with capture_output() as out_all:
print("stdout w przechwyceniu łącznym")
sys.stderr.write("stderr w przechwyceniu łącznym\n")
print("Łączne wyjście:", out_all.getvalue().strip())
with capture_stdout_tee() as tee_out:
print("Wyjście widoczne i przechwycone (Tee)")
print("Bufor Tee:", tee_out.getvalue().strip())
with OutputCapture() as class_capture:
print("Przechwycenie przy użyciu menedżera klasowego")
print("Bufor menedżera klasowego:", class_capture.getvalue().strip())
# ==========================
# Uruchomienie główne
# ==========================
if __name__ == "__main__":
demo_classes()
demo_context_managers()