Programowanie i projektowanie obiektowe
Obiekty i klasy w Pythonie
Paweł Daniluk
Wydział Fizyki
Jesień 2016
Klasy i obiekty
Klasy w implementacji odpowiadają klasom projektowym.
Obiekty są instancjami klas.
Przynależność do klasy określa zakres odpowiedzialności obiektów.
Każdy obiekt należy do pewnej klasy.
Klasa określa funkcjonalności (metody) obiektów.
Każdy obiekt odpowiada za wartości swoich atrybutów. Metody określone przez klasę odwołują się do atrybutów przechowywanych w obiekcie.
Czy klasy mogą być obiektami?
Klasy i obiekty
Klasy w implementacji odpowiadają klasom projektowym.
Obiekty są instancjami klas.
Przynależność do klasy określa zakres odpowiedzialności obiektów.
Każdy obiekt należy do pewnej klasy.
Klasa określa funkcjonalności (metody) obiektów.
Każdy obiekt odpowiada za wartości swoich atrybutów. Metody określone przez klasę odwołują się do atrybutów przechowywanych w obiekcie.
Czy klasy mogą być obiektami?
Klasy i obiekty
Klasy w implementacji odpowiadają klasom projektowym.
Obiekty są instancjami klas.
Przynależność do klasy określa zakres odpowiedzialności obiektów.
Każdy obiekt należy do pewnej klasy.
Klasa określa funkcjonalności (metody) obiektów.
Każdy obiekt odpowiada za wartości swoich atrybutów.
Metody określone przez klasę odwołują się do atrybutów przechowywanych w obiekcie.
Czy klasy mogą być obiektami?
Klasy i obiekty
Klasy w implementacji odpowiadają klasom projektowym.
Obiekty są instancjami klas.
Przynależność do klasy określa zakres odpowiedzialności obiektów.
Każdy obiekt należy do pewnej klasy.
Klasa określa funkcjonalności (metody) obiektów.
Każdy obiekt odpowiada za wartości swoich atrybutów.
Metody określone przez klasę odwołują się do atrybutów przechowywanych w obiekcie.
Czy klasy mogą być obiektami?
Klasy i obiekty
Klasy w implementacji odpowiadają klasom projektowym.
Obiekty są instancjami klas.
Przynależność do klasy określa zakres odpowiedzialności obiektów.
Każdy obiekt należy do pewnej klasy.
Klasa określa funkcjonalności (metody) obiektów.
Każdy obiekt odpowiada za wartości swoich atrybutów.
Metody określone przez klasę odwołują się do atrybutów przechowywanych
Najprostszy obiekt
c l a s s A : pass
Klasa A nie ma żadnych metod, ale może mieć atrybuty.
>>> a=A ( )
>>> a . x
T r a c e b a c k ( most r e c e n t c a l l l a s t ) : F i l e "<s t d i n >" , l i n e 1 , i n <module>
A t t r i b u t e E r r o r : A i n s t a n c e h a s no a t t r i b u t e ’ x ’
>>> a . x=1
>>> a . x 1
>>>
Atrybuty
W Pythonie atrybuty obiektów działają podobnie jak zmienne. Tworzymy je przez pierwsze przypisanie.
Czy to oznacza, że nie można określić w definicji klasy zakresu odpowiedzialności za przechowywanie danych?
Dobre pytanie...
Atrybuty
W Pythonie atrybuty obiektów działają podobnie jak zmienne. Tworzymy je przez pierwsze przypisanie.
Czy to oznacza, że nie można określić w definicji klasy zakresu odpowiedzialności za przechowywanie danych?
Dobre pytanie...
Atrybuty
W Pythonie atrybuty obiektów działają podobnie jak zmienne. Tworzymy je przez pierwsze przypisanie.
Czy to oznacza, że nie można określić w definicji klasy zakresu odpowiedzialności za przechowywanie danych?
Dobre pytanie...
Metody
Metody są definiowane w klasach.
c l a s s Lew :
d e f t a l k ( s e l f ) :
p r i n t " J e s t e m ␣ l e w "
>>> l =Lew ( )
>>> l . t a l k ( ) J e s t e m l e w
>>>
Metody
Metody są definiowane w klasach.
c l a s s Lew :
d e f t a l k ( s e l f ) :
p r i n t " J e s t e m ␣ l e w "
Definicja metody jest podobna do definicji funkcji. Pierwszy argument (self) jest obligatoryjny...
Metody
Definicja metody jest podobna do definicji funkcji. Pierwszy argument (self) jest obligatoryjny...
... i służy do odwoływania się do obiektu, dla którego metoda została wywołana.
d e f s e t H u n g r y ( s e l f , v a l ) : s e l f . h u n g r y=v a l
d e f t a l k M o r e ( s e l f ) : s e l f . t a l k ( ) i f s e l f . h u n g r y :
p r i n t " g l o d n y ␣ l e w "
>>> l=Lew ( )
>>> l . t a l k ( ) J e s t e m l e w
>>> l . s e t H u n g r y ( True )
>>> l . t a l k M o r e ( ) J e s t e m l e w
g l o d n y l e w
>>>
Oczywiście do atrybutu hungry możemy również dostawać się bezpośrednio.
Inicjalizacja
Na początku lew jest popsuty.
>>> l =Lew ( )
>>> l . t a l k M o r e ( ) J e s t e m l e w
T r a c e b a c k ( most r e c e n t c a l l l a s t ) : F i l e "<s t d i n >" , l i n e 1 , i n <module>
F i l e "<s t d i n >" , l i n e 9 , i n t a l k M o r e
A t t r i b u t e E r r o r : Lew i n s t a n c e h a s no a t t r i b u t e ’ h u n g r y ’
Metoda __init__
Dziedziczenie
c l a s s GroznyLew ( Lew ) : d e f t a l k M o r e ( s e l f ) :
s e l f . t a l k ( )
p r i n t " g r o z n y ␣ lew , "
p r i n t " s p o t k a c ␣ mnie ␣ z n a c z y ␣ p e c h . "
i f s e l f . h u n g r y :
p r i n t " W s z y s t k i c h ␣ zjem , ␣ a z ␣ do ␣ dna . "
p r i n t " Rety , ␣ l e p i e j ␣ n i e ␣ s p o t k a c ␣ l w a . "
Metoda talk jest zdefiniowana jest w klasie Lew.
Dziedziczenie
>>> g l=GroznyLew ( )
>>> g l . t a l k ( ) J e s t e m l e w
>>> g l . s e t H u n g r y ( True )
>>> g l . t a l k M o r e ( ) J e s t e m l e w
g r o z n y lew ,
s p o t k a c mnie z n a c z y p e c h . W s z y s t k i c h zjem , a z do dna . Rety , l e p i e j n i e s p o t k a c l w a .
Ograniczenia dostępu
W Pythonie nie ma możliwości określania poziomu dostępności metod i atrybutów. Są dobrowolne konwencje
Składowe o nazwach zaczynających się od znaku “_” są uznawane za niedostępne publicznie i/lub zależne od implementacji. W szczególności nie należy zakładać, że w kolejnych wersjach programów pozostaną
niezmienone.
Ograniczenia dostępu
Składowe o nazwach zaczynających się od znaków “__” są “prywatne” w specyficzny sposób.
Wewnątrz definicji klasy identyfikator postaci “__ident” jest zamieniany na “_Klasa__ident’’
Ograniczenia dostępu
c l a s s Lew : . . .
d e f __talkMore ( s e l f ) : s e l f . t a l k ( ) i f s e l f . h u n g r y :
p r i n t " g l o d n y ␣ l e w "
d e f t a l k M o r e ( s e l f ) : s e l f . __talkMore ( )
d e f t a l k S a f e ( s e l f ) : s e l f . __talkMore ( )
c l a s s GroznyLew ( Lew ) : d e f __talkMore ( s e l f ) :
s e l f . t a l k ( )
p r i n t " g r o z n y ␣ lew , "
p r i n t " s p o t k a c ␣ mnie ␣ z n a c z y ␣ p e c h . "
i f s e l f . h u n g r y :
p r i n t " W s z y s t k i c h ␣ zjem , ␣ a z ␣ do ␣ dna . "
p r i n t " Rety , ␣ l e p i e j ␣ n i e ␣ s p o t k a c ␣ l w a . "
d e f t a l k M o r e ( s e l f ) : s e l f . __talkMore ( ) d e f t a l k M e a n ( s e l f ) :
s e l f . __talkMore ( )
Ograniczenia dostępu
>>> l =Lew ( )
>>> l . t a l k M o r e ( ) J e s t e m l e w g l o d n y l e w
>>> l . t a l k S a f e ( ) J e s t e m l e w g l o d n y l e w
Ograniczenia dostępu
>>> g l=GroznyLew ( )
>>> g l . t a l k M o r e ( ) J e s t e m l e w
g r o z n y lew ,
s p o t k a c mnie z n a c z y p e c h . W s z y s t k i c h zjem , a z do dna . Rety , l e p i e j n i e s p o t k a c l w a .
>>> g l . t a l k S a f e ( ) J e s t e m l e w
g l o d n y l e w
>>> g l . t a l k M e a n ( ) J e s t e m l e w
g r o z n y lew ,
s p o t k a c mnie z n a c z y p e c h . W s z y s t k i c h zjem , a z do dna . Rety , l e p i e j n i e s p o t k a c l w a .
>>>
Duck typing
When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.
Na zmienną można przypisać referencję do dowolnego obiektu. Próba odwołania się do nieistniejącej składowej skutkuje błędem wykonania.
Duck typing
When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.
Na zmienną można przypisać referencję do dowolnego obiektu. Próba odwołania się do nieistniejącej składowej skutkuje błędem wykonania.
Duck typing c.d.
Zalety
Można używać w jednym kontekście obiektów nie mających wspólnej nadklasy zawierającej wymagane składowe.
Nie trzeba stosować rzutowań, interfejsów, typów generycznych ani wzorców.
Łatwiejsze projektowanie.
Wady
Proste błędy (np. literówki), mogłyby zostać wykryte na etapie kompilacji.
Ścisły system typów zabezpiecza przed podawaniem niewłaściwych argumentów itp.
Duck typing c.d.
Zalety
Można używać w jednym kontekście obiektów nie mających wspólnej nadklasy zawierającej wymagane składowe.
Nie trzeba stosować rzutowań, interfejsów, typów generycznych ani wzorców.
Łatwiejsze projektowanie.
Wady
Proste błędy (np. literówki), mogłyby zostać wykryte na etapie kompilacji.
Ścisły system typów zabezpiecza przed podawaniem niewłaściwych argumentów itp.
Python quirks – metoda __init__
Metoda __init__ nie jest konstruktorem.
Jeżeli podczas inicjalizacji podklasy ma zostać wywołana metoda __init__
z nadklasy, trzeba to zrobić wprost.
B a s e C l a s s . __init__ ( s e l f , [ a r g s . . . ] )
Python quirks – metody to funkcje
>>> l =Lew ( )
>>> l . t a l k M o r e ( ) J e s t e m l e w
>>> Lew . t a l k M o r e ( l ) J e s t e m l e w
>>> Lew . s e t H u n g r y ( l , True )
>>> Lew . t a l k M o r e ( l ) J e s t e m l e w
g l o d n y l e w
>>>
Python quirks – argumenty metod/funkcji
Domyślne wartości
d e f __init__ ( s e l f , h u n g r y=True ) : . . .
Argumenty nazwane
d e f p a r r o t ( v o l t a g e , s t a t e= ’ a ␣ s t i f f ’ , a c t i o n= ’ voom ’ , t y p e= ’ N o r w e g i a n ␣ B l u e ’ ) :
p r i n t "−−␣ T h i s ␣ p a r r o t ␣ w o u l d n ’ t " , a c t i o n ,
p r i n t " i f ␣ you ␣ p u t " , v o l t a g e , " v o l t s ␣ t h r o u g h ␣ i t . "
p r i n t "−−␣ L o v e l y ␣ plumage , ␣ t h e " , t y p e p r i n t "−−␣ I t ’ s " , s t a t e , " ! "
p a r r o t ( 1 0 0 0 ) # 1 p o s i t i o n a l a r g u m e n t p a r r o t ( v o l t a g e =1000) # 1 k e y w o r d a r g u m e n t
p a r r o t ( v o l t a g e =1000000 , a c t i o n= ’VOOOOOM’ ) # 2 k e y w o r d a r g s p a r r o t ( a c t i o n= ’VOOOOOM’ , v o l t a g e =1000000) # 2 k e y w o r d a r g s p a r r o t ( ’ a ␣ m i l l i o n ’ , ’ b e r e f t ␣ o f ␣ l i f e ’ , ’ jump ’ )
# 3 p o s i t i o n a l a r g u m e n t s
p a r r o t ( ’ a ␣ t h o u s a n d ’ , s t a t e= ’ p u s h i n g ␣ up ␣ t h e ␣ d a i s i e s ’ )
# 1 p o s i t i o n a l , 1 k e y w o r d