PEP 367 - New Super (Py2.6)
PEP 3135 - New Super (Py3)
Klasy służą jako fabryki generujące wiele obiektów instancji, ale również pozwalają na modyfikacje za pomocą wprowadzania nowych komponentów (klas podrzędnych) w miejsce modyfikowania istniejących komponentów w miejscu. Python pozwala klasom na dziedziczenie po innych klasach, umożliwiając tworzenie hierarchii klas specjalizujących jakieś zachowanie za pomocą redefiniowania atrybutów.
Klasy nadrzędne są wymieniane w nawiasach w nagłówku instrukcji class. Instancje klasy podrzędnej dziedziczą atrybuty po wszystkich klasach nadrzędnych.
class C1: # nowy obiekt klasy
pass
class C2: # nowy obiekt klasy
message = "GvR" # atrybut klasy C2
class C3(C1, C2): # dziedziczenie wielokrotne
def __init__(self, who):
"""Konstruktor instancji klasy C3."""
self.name = who
# C3 to klasa podrzędna.
# C1 i C2 to klasy nadrzędne.
I1 = C3("Adam") # instancja klasy C3
I2 = C3("Bogdan") # instancja klasy C3
print(I1.name) # kolejność przeszukiwania: I1, C3, C1, C2
# Tu przeszukiwanie zakończy się na I1,
# ponieważ 'name' jest atrybutem instancji.
print(I1.message) # kolejność przeszukiwania: I1, C3, C1, C2
# Tu przeszukiwanie dotrze aż do klasy C2.
I1.message = "Python" # atrybut tylko instancji I1
print(I1.message) # Python, odczyt atrybutu instancji I1
print(I2.message) # GvR, dochodzimy do atrybutu klasy C2
print(C2.message) # GvR, odczytanie wprost atrybutu klasy
print(C3.__bases__) # krotka klas nadrzędnych
Jeżeli obiekt pochodzi z instrukcji class, to wyrażenie obiekt.atrybut uruchamia w Pythonie wyszukiwanie. Python przeszukuje drzewo połączonych obiektów, szukając pierwszego wystąpienia atrybutu. Najpierw szuka w obiekcie, a następnie we wszystkich klasach powyżej niego, od dołu do góry i od lewej do prawej.
class FirstClass:
"""Przykładowa pierwsza klasa."""
def __init__(self, x):
"""Konstruktor instancji klasy FirstClass."""
instrukcje
class SecondClass(FirstClass):
"""Przykładowa druga klasa, dziedziczona z pierwszej."""
def __init__(self, x, y):
"""Konstruktor instancji klasy SecondClass."""
# Wywołanie kostruktora klasy nadrzędnej.
FirstClass.__init__(self, x)
#super().__init__(x) # nie musimy znać nazwy FirstClass (Py3)
# Nie musimy zmieniać kodu __init__ po zmianie FirstClass na NextClass.
instrukcje # nowe działania inicjalizacyjne
Klasy są atrybutami w modułach. Nazwa klasy jest zmienną przechowującą referencję do obiektu klasy.
# Moduł persons.py
"""Moduł z narzędziami do opisu osób.""" # docstring modułu
class Person:
"""Klasa reprezentująca osoby."""
def __init__(self, who):
"""Konstruktor osoby."""
self.name = who
value = 2012
# Kod testujący moduł.
if __name__ == "__main__":
adam = Person("Adam")
print(adam.name)
print(value)
# Moduł główny
import persons # import modułu 'persons'
student = persons.Person("Anna") # tworzenie instancji
print(student.name) # Anna, atrybut instancji
print(persons.value) # 2012, potrzebna kwalifikacja
# Poznane narzędzia. isinstance(instancja, klasa_lub_krotka_klas) instancja.__class__ # łącze do klasy instancja.__class__.__name__ # nazwa klasy instancja.__dict__.keys() # przestrzeń nazw instancji (tylko atrybuty instancji) dir(instancja) # jw + odziedziczone atrybuty z klas klasa.__dict__.keys() # przestrzeń nazw klasy klasa.__bases__ # krotka klas nadrzędnych
Przykład z książki: Joel Spolsky, Sztuka pisania oprogramowania. Wybór i redakcja Joel Spolsky, Helion.
# Budujemy hierarchię klas.
class Pet:
"""Klasa dla ulubieńców."""
def speak(self):
pass # odkładamy definicję na później
class Cat(Pet):
"""Klasa dla kotów."""
def speak(self):
print("miau!")
class Dog(Pet):
"""Klasa dla psów."""
def speak(self):
print("hau!")
# Klasa nie wywiedziona z Pet.
class Person:
"""Klasa dla osób."""
def speak(self):
print("witam!")
def drive(self):
print("piii!")
# Zwykła funkcja, a nie metoda.
def command(pet):
pet.speak()
pets = [Cat(), Dog(), Person()] # działają konstruktory klas
# Przykład polimorfizmu Pythona.
# Funkcja oczekuje określonego interfejsu (metody 'speak'),
# a nie określonego typu argumentu.
for pet in pets:
command(pet)