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)