kurs-pythona-czesc-iii-software-developers-journal.pdf

(383 KB) Pobierz
PROGRAMOWANIE PYTHON
Kurs Pythona
Odcinek 3: Model obiektowy
Dwa pierwsze odcinki miały za zadanie zapoznać nas
z podstawowymi cechami języka i środowiska Python.
Ostatnią wielką niewiadomą pozostały dla nas klasy.
Po ich poznaniu będziemy mogli uznać, że rozumiemy
fundamenty Pythona. Do dzieła!
Dowiesz się:
• Jak korzystać z wbudowanych oraz bibliotecznych klas i obiektów;
• Jak zbudować własną klasę;
• Czym są dekoratory.
Powinieneś wiedzieć:
• Jak zainstalować i uruchomić interpreter Python 2.6 ;
• Jak używać wbudowanych w Pythona list, słowników, krotek i
zbiorów.
M odel klasowy Pythona składa się z dość prostej
dami. O funkcjach zdążyliśmy sobie opowiedzieć sporo
już ostatnim razem. Zdążyliśmy też wspomnieć o wbudo-
wanych funkcjach i związanych z nimi funkcjach specjal-
nych mających w nazwie po dwa znaki "_" z przodu i z ty-
łu. W przypadku metod funkcje te nabierają szczególne-
go znaczenia, ponieważ pozwalają klasie implementować
szereg opcjonalnych funkcjonalności takich jak ładna re-
prezentacja tekstowa w metodach __unicode__ i __str__
czy możliwość porównywania arytmetycznego ze sobą
różnych obiektów danej klasy, w metodach __lt__ (mniej-
szy), __gt__ (większy), __eq__ (równy) itd.
Jedną z takich metod specjalnych jest metoda __init__ ,
nazywana w pewnym uproszczeniu konstruktorem [1]. To
znaczy, że tworząc nowe obiekty, wywołujemy właśnie tę
metodę:
składni i funkcjonalności, która jest mieszanką
systemów obiektowych znanych w C++, Perlu
i Objective-C. Od każdego z tych modeli różni się jednak
na tyle, że warto przejść przez wszystkie cechy klas py-
thonowych dokładnie.
Podstawowa klasa
Zacznijmy od razu od przykładu. Na Listingu 1 znajduje
się prosty model klasowy, który prezentuje wszystkie pod-
stawowe cechy języka. Prezentowane klasy opisują odpo-
wiednio "grzałkę", "dmuchawę" oraz ich połączenie, czy-
li "suszarkę do włosów". Zwróć uwagę, że mimo tego, że
nie omówiłem jeszcze żadnej kwestii dotyczącej klas, już
jesteś w stanie dużo zrozumieć.
Róbta co chceta
Najbardziej fundamentalną cechą klas i obiektów w Py-
thonie jest to, że nie ma w nich podziału na składowe pu-
bliczne i prywatne. Oznacza to, że każdy użytkownik da-
nego obiektu ma pełen dostęp do wszystkich metod i pól
zadeklarowanych w danej klasie. Użytkownikom Javy,
C++ i C# wyda się to nie do pomyślenia, jednak taka de-
cyzja powoduje szereg bardzo pozytywnych skutków,
o czym powiemy sobie później. Ustalanie, jakie składniki
klasy należą do jej wewnętrznej implementacji, jest możli-
we przez konwencję, zgodnie z którą nazwy takich skład-
ników poprzedza się pojedynczym znakiem "_".
hairdryer = Hairdryer()
normal_heater = Heater()
hot_heater = Heater(max_temp=80)
Jak widać, pierwszym argumentem metody _ _ init _
_ i wszystkich innych metod w klasach pythonowych
jest self , czyli zmienna wskazująca na aktualny obiekt.
Zmienna ta jest wpisywana do argumentów automatycz-
nie podczas wywołania metody, więc nie musimy jej do-
datkowo podawać, np.:
>>> hairdryer.dry(5)
Heating to 40 degrees for 5 minutes.
>>> hairdryer.max_temp
50
Metody
Funkcje znajdujące się wewnątrz klasy nazywamy meto-
54
9/2010
1241957280.029.png 1241957280.030.png 1241957280.031.png
 
1241957280.001.png 1241957280.002.png 1241957280.003.png 1241957280.004.png 1241957280.005.png 1241957280.006.png 1241957280.007.png 1241957280.008.png 1241957280.009.png 1241957280.010.png
Model obiektowy
tów danej klasy. W klasie Blower w metodzie __init__()
znajdziemy natomiast pola instancji, czyli takie, które są
zawarte tylko w konkretnym obiekcie (czyli w pojedynczej
instancji danej klasy). Inne języki posiadają podobne roz-
graniczenie, nazywając często pola klasowe statycznymi.
Ciekawą cechą, którą można zaobserwować w przykła-
dzie, jest fakt, że w metodzie heat() klasy Heater odwo-
łujemy się do pól klasowych tak, jak gdyby były one pola-
mi instancji. Jest to często używany skrót, który dodatko-
wo pozwala w razie potrzeby na przesłonienie danego po-
la klasowego polem instancji.
Przykład takiej techniki znajduje się w konstruktorze klasy
Heater, gdzie jeżeli podamy opcjonalny argument max_temp ,
konstruktor przesłoni nam domyślną wartość pola klasowe-
go nowym polem instancji. Powoduje to, że klasa w ogólno-
ści zachowuje swoje domyślne ustawienie, ale obiekty mo-
gą to ustawienie dostosowywać do własnych potrzeb.
>>> hot_heater.max_temp
80
automatycznie dołączy do wykonania metody pierwszy
argument self wskazujący na obiekt hairdryer . Argu-
ment 45 trai więc do zmiennej how _ long .
Niektóre języki umożliwiają przygotowywanie wielu wer-
sji tej samej metody, różniących się typem lub liczbą argu-
mentów. W świecie Pythona taka możliwość nie jest po-
trzebna ze względu na obecność argumentów opcjonal-
nych. Przykład takiego argumentu mamy w konstruktorze
klasy Heater, który przez to możemy wołać zarówno nie
podając żadnych dodatkowych argumentów, jak również
specyfikując niestandardową temperaturę maksymalną.
Pola
W prezentowanym na Listingu 1 przykładzie widać dwa
przykłady pól: klasa Heater prezentuje pola klasowe, czy-
li takie, których wartość jest wspólna dla wszystkich obiek-
Dziedziczenie
Jak widać w naszym przykładzie, Python obsługuje wielo-
krotne dziedziczenie. Jest to funkcjonalność stosunkowo
rzadko wykorzystywana i głównie do "przyklejania" dodat-
kowej funkcjonalności do istniejących klas, tak też zrobili-
śmy w naszym przykładzie, gdzie suszarka jest po prostu
grzałką z dmuchawą.
Klasy, po których dziedziczymy, wymieniamy po prze-
cinku w nawiasach za nazwą klasy. Domyślnie, jeżeli nie
chcemy dziedziczyć z jakiejś klasy, powinniśmy dziedzi-
czyć z klasy object . Klasy, które nie dziedziczą po tym ty-
pie, są w świecie Pythona znane jako klasy starego stylu
i posiadają szereg niewygodnych ograniczeń [2]. Stąd, je-
żeli tylko możemy, powinniśmy dziedziczyć z object .
Klasy, po których dziedziczymy w świecie Pythona, na-
zywamy klasami bazowymi . W każdym przypadku, kiedy
Listing 1. Podstawowa struktura klas
class Heater ( object ):
min_temp = 28
max_temp = 50
def __init__ ( self , max_temp = None ):
if max_temp :
self . max_temp = max_temp
def heat ( self , temp , how_long ):
if self . min_temp <= temp <= self . max_temp :
print "Heating to" , temp ,
print "degrees for" , how_long , "minutes."
else :
raise ValueError , "Temperature out or range."
Listing 2. Dziedziczenie z wbudowanego typu
class Blower ( object ):
def __init__ ( self ):
self . blowing = False
>>> class AttrDict ( dict ):
... def __getattr__ ( self , attr ):
... try :
... return self [ attr ]
... except KeyError :
... return ''
>>> a = AttrDict ()
>>> a [ 'monty' ] = 'python'
>>> a [ 'star' ] = 'bucks'
>>> a
{ 'star' : 'bucks' , 'monty' : 'python' }
>>> a . star
'bucks'
>>> a . monty
'python'
>>> a . bill
''
def blow ( self ):
self . blowing = True
def stop ( self ):
self . blowing = False
class Hairdryer ( Heater , Blower ):
def __init__ ( self ):
super ( Hairdryer , self ) . __init__ ()
def dry ( self , how_long ):
self . blow ()
self . heat ( 40 , how_long )
www.sdjournal.org
55
1241957280.011.png 1241957280.012.png 1241957280.013.png 1241957280.014.png 1241957280.015.png 1241957280.016.png 1241957280.017.png 1241957280.018.png 1241957280.019.png 1241957280.020.png 1241957280.021.png 1241957280.022.png
 
PROGRAMOWANIE PYTHON
chcemy odnieść się do jakiejś metody lub pola z klasy ba-
zowej, możemy to zrobić bez żadnego kłopotu. Przykład
widać w metodzie dry() klasy Hairdryer , która odwołuje
się do metod blow() i heat() zdefiniowanych w klasach
bazowych.
Może się jednak zdarzyć sytuacja, że w aktualnej klasie
definiujemy składnik o takiej samej nazwie jak występu-
jący w klasie bazowej. Wówczas trzeba użyć konstrukcji
super() , która umożliwia wykonanie metody lub uzyska-
nie dostępu do pola z klasy bazowej [3].
Po wbudowanych typach też można dziedziczyć, co
prezentuje Listing 2. Mamy tam definicję magicznego ty-
pu, który jest jednocześnie słownikiem, ale także udostęp-
nia elementy słownika jako swoje atrybuty. Jest to możliwe
dzięki prostej implementacji specjalnej metody __getattr_
_ . Dodatkowo w metodzie tej zapewniliśmy, że w przypad-
ku odwołania się do nieistniejącego atrybutu otrzymamy
pusty łańcuch znaków zamiast rzuconego wyjątku.
Listing 3. Właściwości
>>> class Traditional ( object ):
... ield = 'A'
>>> t = Traditional ()
>>> t . ield
'A'
>>> t . ield = 'B'
>>> t . ield
'B'
>>> class Smart ( object ):
... _data = 'A'
... @ property
... def ield ( self ):
... return self . _data
... @ ield . setter
... def ield ( self , value ):
... self . _data = value
...
>>> s = Smart ()
>>> s . ield
'A'
>>> s . ield = 'B'
>>> s . ield
'B'
>>> class Smart ( object ):
... @ property
... def ield ( self ):
... return 'A'
>>> s = Smart ()
>>> s . ield
'A'
Pola są lepsze niż metody
W świecie Pythona bardzo często używaną cechą jest
możliwość bezpośredniego odwołania się do pól danej
klasy czy obiektu. Wywołania typu osoba.data_urodzenia
lub samochod.silnik.pojemnoc są na porządku dziennym.
Takie rozwiązanie ma szereg zalet, z których największą
jest fakt, że tak pisany kod jest bardzo czytelny. Dodatko-
wo przez to, że odwołujemy się bezpośrednio do pola, wy-
konanie takiego żądania jest całkiem wydajne.
Programiści Javy mogą w tym momencie zaalarmować,
że takie zachowanie niesie za sobą zagrożenie! Mianowi-
cie, możliwe, że później zmienimy architekturę naszej kla-
sy i już nie będzie można bezpośrednio pobrać daty uro-
dzenia danej osoby z pola, ale trzeba będzie wykonać
metodę. W takim przypadku trzeba będzie edytować kod,
który korzysta z danej klasy, a to jest czasochłonne i nie-
bezpieczne.
Na szczęście w Pythonie możemy się od tego odciąć
poprzez właściwości , czyli specjalne pola, które tak na-
prawdę są metodkami wywołanymi za naszymi plecami.
Przykład widzimy w Listingu 3. Za pomocą specjalnej kon-
strukcji nazywanej dekoratorem, którą poprzedzamy defi-
nicję metody, oznaczamy ją jako właściwość, czyli metod-
kę przebraną za pole. Jak widać, można nawet definiować
grupy metod, które umożliwiają nadawanie takim "polom"
nowych wartości.
Morał z tej historii jest taki, że należy korzystać, kiedy
się tylko da, z tradycyjnych pól. W razie potrzeby moż-
na je zamienić właściwościami, co ma tę dodatkową za-
letę, że sposób korzystania z takiej klasy pozostaje cały
czas prosty.
Przypisy
[1] Właściwie konstrukcją obiektu zajmuje się inna metoda
_ _ new _ _ , a metoda _ _ init _ _ pozwala jedynie
logicznie zainicjalizować dany obiekt. Jest to jednak za-
awansowane zagadnienie i dla większości potrzeb moż-
na myśleć o _ _ init _ _ jako o konstruktorze obiek-
tów danej klasy.
[2] Jednym z takich ograniczeń jest brak dostępu do funkcji
super() .
[3] O tym, jaka to konkretnie klasa, deiniuje zasada na-
zywająca się MRO (ang. Method Resolution Order ).
Jest to zaawansowany temat, dla ciekawskich: http://
www.enterthefoo.com/static/prez/mro/index.html lub http:
//www.python.org/download/releases/2.3/mro/ .
W następnym odcinku
W następnym miesiącu wykorzystamy wiedzę, którą zgro-
madziliśmy do operacji na plikach i przetwarzania tekstu.
Do zobaczenia za miesiąc!
ŁUKASZ LANGA
programuje w Pythonie od 8 lat, aktualnie współpracuje z STX
Next, rozwijając oprogramowanie dla sektora bankowego.
Prywatnie miłośnik muzyki fortepianowej, początkujący oj-
ciec i mąż. Adres e-mail autora: lukasz@langa.pl.
56
9/2010
1241957280.023.png 1241957280.024.png 1241957280.025.png 1241957280.026.png 1241957280.027.png 1241957280.028.png
Zgłoś jeśli naruszono regulamin