• Nie Znaleziono Wyników

Programowanie i projektowanie obiektowe Python od środka Paweł Daniluk

N/A
N/A
Protected

Academic year: 2021

Share "Programowanie i projektowanie obiektowe Python od środka Paweł Daniluk"

Copied!
29
0
0

Pełen tekst

(1)

Programowanie i projektowanie obiektowe

Python od środka

Paweł Daniluk

Wydział Fizyki

Jesień 2016

(2)

Zasięgi nazw (ang. scopes)

Przestrzeń nazw

Mapowanie nazw (zmiennych) do wartości (obiektów). Jest związane z:

klasami obiektami modułami

Dodatkowo występują przestrzenie:

lokalna (locals()) globalna (globals()) wbudowana (__builtin__)

Przestrzenie nazw są niezależne.

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 2 / 26

(3)

Zasięgi nazw (ang. scopes)

Zasięgi

Zasięgi są związane z funkcjami.

Zmienne występujące w funkcji są widoczne w jej leksykalnym obrębie i należą do lokalnej przestrzeni nazw.

Przypisanie zawsze dotyczy najsilniej zagnieżdżonego zasięgu.

Zasięg, w którym funkcja została zdefiniowana istnieje wraz z nią.

(4)

Zasięgi – przykłady

d e f f ( ) : p r i n t( x ) x = ’ g l o b a l ’ f ( )

d e f f ( ) : x = ’ f ’

p r i n t( x ) x = ’ g l o b a l ’

p r i n t( x ) f ( ) p r i n t( x )

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 4 / 26

(5)

Zasięgi – przykłady

d e f f ( ) : p r i n t( x ) x = ’ f ’ x = ’ g l o b a l ’ f ( )

d e f f ( ) : p r i n t( x ) d e f g ( ) :

g l o b a l x p r i n t( x ) x = ’ g ’ x = ’ g l o b a l ’ f ( )

g ( ) f ( )

(6)

Zasięgi – przykłady

x = ’ g l o b a l ’ d e f f ( ) :

d e f g ( ) : g l o b a l x p r i n t( x ) x = ’ f ’ g ( ) f ( ) d e f f ( ) :

d e f g ( ) :

n o n l o c a l x x = ’ g ’ x = ’ f ’ g ( )

p r i n t( x ) x = ’ g l o b a l ’ f ( )

p r i n t( x )

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 6 / 26

(7)

Implementacja przestrzeni nazw

Przestrzenie nazw są zazwyczaj implementowane przy pomocy słowników.

Często słownik dostępny jest przez atrybut __dict__.

Funkcje locals() globals()

dir([object]) – zwraca zmienne w bieżącym zasięgu lub atrybuty dostępne w obiekcie (niekoniecznie własne)

Można zrobić klasę, której obiekty nie mają atrybutu __dict__. Służy do tego atrybut __slots__.

c l a s s A( o b j e c t ) :

__slots__=[ ’ a1 ’ , ’ a2 ’ ] Klasa A ma tylko dwa atrybuty a1 i a2.

(8)

Typy i obiekty

Każda wartość w Pythonie jest obiektem (nawet liczba).

Każdy obiekt ma unikalny identyfikator (id()) Każdy obiekt ma typ (type())

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 8 / 26

(9)

Typy wbudowane w Pythona

None

NotImplemented Ellipsis numbers.Number

I numbers.Integral

I numbers.Real

I numbers.Complex

Sequences

I immutable

F strings

F unicode

F tuples

I mutable

F lists

F byte arrays

(10)

Typy wbudowane w Pythona

sets

I set

I frozenset

mappings callable types

I user-defined functions

I user-defined methods

I generator functions

I built-in functions

I built-in methods

I class types (new-style)

I classic classes

I class instances (czasem)

modules classes

class instances files

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 10 / 26

(11)

Funkcje są obiektami

Funkcje mogą być traktowane jak wartości:

przypisywane na zmienną, przekazywane jako parametry.

Funkcje mogą mieć atrybuty.

>>> def f():

... pass

...

>>> f.atr=1

>>> f.atr 1

(12)

Funkcje są obiektami

Funkcje nazwane

d e f f ( x ) : r e t u r n x+1

Funkcje anonimowe

f=lambda x : x+1

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 12 / 26

(13)

Czym się różni funkcja od metody?

>>> class A():

... def f(self):

... pass

...

>>> A.__dict__

’__module__’: ’__main__’, ’__doc__’: None, ’f’: <function f at 0x10e3615f0>

>>> A.f

<unbound method A.f>

>>> A().f

<bound method A.f of <__main__.A instance at 0x10e1fdb90>>

Funkcje są atrybutami klas.

Pobranie atrybutu, który jest funkcją, skutkuje zwróceniem metody.

Metoda może być przywiązana lub nie.

(14)

Czym się różni funkcja od metody? c.d.

Metody mają atrybuty:

im_class – klasa

im_func – funkcja (atrybut klasy)

im_self – obiekt (określony tylko w metodzie przywiązanej)

Metoda przywiązana

Obiekt, który można wywołać (ma metodę __call__). Wywołanie powoduje przekazanie do funkcji parametru self oraz pozostałych podanych w wywołaniu metody.

Metoda nieprzywiązana

Metoda nieprzywiązana różni się od funkcji tym, że weryfikuje, czy pierwszy parametr jest instancją klasy, z której metoda pochodzi.

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 14 / 26

(15)

Nowe i stare klasy (new-style classes, classic classes)

Classic classes

Niezależne od systemu typów.

Instancje klas są typu

<type ’instance’>.

New-style classes

Włączone w system typów.

Typ instancji jest równy jej klasie.

Dziedziczą z klasy object.

Możliwości klas w nowym stylu metody statyczne i klasowe cechy i deskryptory

lepsze wielodziedziczenie metaklasy

__slots__

(16)

Wielodziedziczenie (ang. multiple inheritance)

Czasami występuje potrzeba opisu klas, które łączą w sobie cechy kilku klas nadrzędnych (np. latająca łódź).

Wielodziedziczenie może powodować straszne problemy (Deadly Diamond of Death). Niezwykle istotne są reguły wyszukiwania metod (Method Resolution Order – MRO).

Stare i nowe klasy różnią się MRO. W nowych klasach zawsze występuje diament (bo dziedziczą z object).

Linearyzacja

Kolejność klas w MRO zachowuje porządek wynikający z dziedziczenia (nadklasa zawsze po podklasie) i kolejności występowania nadklas w definicji klasy.

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 16 / 26

(17)

Wielodziedziczenie (ang. multiple inheritance)

Czasami występuje potrzeba opisu klas, które łączą w sobie cechy kilku klas nadrzędnych (np. latająca łódź).

Wielodziedziczenie może powodować straszne problemy (Deadly Diamond of Death). Niezwykle istotne są reguły wyszukiwania metod (Method Resolution Order – MRO).

Stare i nowe klasy różnią się MRO. W nowych klasach zawsze występuje diament (bo dziedziczą z object).

Linearyzacja

Kolejność klas w MRO zachowuje porządek wynikający z dziedziczenia

(nadklasa zawsze po podklasie) i kolejności występowania nadklas w

definicji klasy.

(18)

Wielodziedziczenie c.d.

Niektóre hierarchie nie pozwalają na linearyzację

c l a s s A( o b j e c t ) :

d e f meth ( s e l f ) : r e t u r n "A"

c l a s s B( o b j e c t ) :

d e f meth ( s e l f ) : r e t u r n "B"

c l a s s X(A , B ) : p a s s c l a s s Y(B , A ) : p a s s c l a s s Z (X , Y ) : p a s s

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 17 / 26

(19)

Jak dostać się do nadklasy?

Metoda rozszerzająca zazwyczaj wywołuje metodę z nadklasy.

Problem

c l a s s A( o b j e c t ) :

d e f m( s e l f ) : " s a v e ␣A ’ s ␣ d a t a "

c l a s s B(A ) : d e f m( s e l f ) :

" s a v e ␣B ’ s ␣ d a t a "

A .m( s e l f ) c l a s s C(A ) :

d e f m( s e l f ) :

" s a v e ␣C ’ s ␣ d a t a "

A .m( s e l f ) c l a s s D(B , C ) :

d e f m( s e l f ) :

" s a v e ␣D ’ s ␣ d a t a "

B .m( s e l f ) ; C .m( s e l f )

Wywołanie D.m() spowoduje dwukrotne wykonanie A.m().

(20)

Jak dostać się do nadklasy?

Metoda rozszerzająca zazwyczaj wywołuje metodę z nadklasy.

Problem

c l a s s A( o b j e c t ) :

d e f m( s e l f ) : " s a v e ␣A ’ s ␣ d a t a "

c l a s s B(A ) : d e f m( s e l f ) :

" s a v e ␣B ’ s ␣ d a t a "

A .m( s e l f ) c l a s s C(A ) :

d e f m( s e l f ) :

" s a v e ␣C ’ s ␣ d a t a "

A .m( s e l f ) c l a s s D(B , C ) :

d e f m( s e l f ) :

" s a v e ␣D ’ s ␣ d a t a "

B .m( s e l f ) ; C .m( s e l f )

Wywołanie D.m() spowoduje dwukrotne wykonanie A.m().

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 18 / 26

(21)

Jak dostać się do nadklasy?

c l a s s A( o b j e c t ) :

d e f m( s e l f ) : " s a v e ␣A ’ s ␣ d a t a "

c l a s s B(A ) :

d e f _m( s e l f ) : " s a v e ␣B ’ s ␣ d a t a "

d e f m( s e l f ) : s e l f ._m( ) ; A .m( s e l f ) c l a s s C(A ) :

d e f _m( s e l f ) : " s a v e ␣C ’ s ␣ d a t a "

d e f m( s e l f ) : s e l f ._m( ) ; A .m( s e l f ) c l a s s D(B , C ) :

d e f _m( s e l f ) : " s a v e ␣D ’ s ␣ d a t a "

d e f m( s e l f ) : s e l f ._m( ) ; B ._m( s e l f ) ; C ._m( s e l f ) ; A .m( s e l f )

To rozwiązanie jest poprawne, ale implementacja D musi uwzględnić

istnienie klasy A.

(22)

Jak dostać się do nadklasy?

c l a s s A( o b j e c t ) :

d e f m( s e l f ) : " s a v e ␣A ’ s ␣ d a t a "

c l a s s B(A ) :

d e f _m( s e l f ) : " s a v e ␣B ’ s ␣ d a t a "

d e f m( s e l f ) : s e l f ._m( ) ; A .m( s e l f ) c l a s s C(A ) :

d e f _m( s e l f ) : " s a v e ␣C ’ s ␣ d a t a "

d e f m( s e l f ) : s e l f ._m( ) ; A .m( s e l f ) c l a s s D(B , C ) :

d e f _m( s e l f ) : " s a v e ␣D ’ s ␣ d a t a "

d e f m( s e l f ) : s e l f ._m( ) ; B ._m( s e l f ) ; C ._m( s e l f ) ; A .m( s e l f )

To rozwiązanie jest poprawne, ale implementacja D musi uwzględnić istnienie klasy A.

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 19 / 26

(23)

Strategia następnej metody

c l a s s A( o b j e c t ) :

d e f m( s e l f ) : " s a v e ␣A ’ s ␣ d a t a "

c l a s s B(A ) :

d e f m( s e l f ) : " s a v e ␣B ’ s ␣ d a t a " ; s u p e r (B , s e l f ) .m( ) # C c l a s s C(A ) :

d e f m( s e l f ) : " s a v e ␣C ’ s ␣ d a t a " ; s u p e r ( C , s e l f ) .m( ) # A c l a s s D(B , C ) :

d e f m( s e l f ) : " s a v e ␣D ’ s ␣ d a t a " ; s u p e r (D, s e l f ) .m( ) # B A . __mro__ == (A , o b j e c t)

B . __mro__ == (B , A , o b j e c t) C . __mro__ == ( C , A , o b j e c t) D . __mro__ == (D, B , C , A , o b j e c t)

super(class, obj)

nie musi być nadklasą class jest nadklasą obj.__class__

obj musi być instancją pewnej podklasy class

(24)

Jak powstają metody?

>>> class A(object):

... def f(self): pass

...

>>> A.__dict__[’f’]

<function f at 0x10be7f140>

>>> A.f

<unbound method A.f>

>>> A().f

<bound method A.f of <__main__.A object at 0x10bea10d0>>

Funkcja ma metodę __get__(self, obj, objtype=None).

>>> def g(self):pass ...

>>> g.__get__(None, A)

<unbound method A.g>

>>> g.__get__(A(), A)

<bound method A.g of <__main__.A object at 0x10bea1250>>

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 21 / 26

(25)

Jak powstają metody?

Zamiast funkcji możemy mieć dowolny obiekt, który ma metodę __get__.

c l a s s RandFun ( o b j e c t ) :

d e f __init__ ( s e l f , ∗ a r g s ) : s e l f . f l i s t =a r g s

d e f __get__( s e l f , o b j , o b j t y p e=None ) :

r e t u r n random . c h o i c e ( s e l f . f l i s t ) . __get__( o b j , o b j t y p e )

c l a s s A( o b j e c t ) : d e f f 1 ( s e l f ) :

p r i n t " J e s t e m ␣ f 1 "

d e f f 2 ( s e l f ) :

p r i n t " J e s t e m ␣ f 2 "

d e f g ( s e l f , v a l ) :

p r i n t " J e s t e m ␣ g : ␣ "+s t r ( v a l ) r f =RandFun ( f 1 , f 2 )

r f g=RandFun ( f 1 , f 2 , f g )

(26)

Deskryptory

Obiekt implementujący co najmniej jedną z metod __get__(), __set()__, __delete()__ nazywa się deskryptorem.

c l a s s R e v e a l A c c e s s (o b j e c t ) :

d e f __init__ ( s e l f , i n i t v a l =None , name= ’ v a r ’ ) : s e l f . v a l = i n i t v a l

s e l f . name = name

d e f __get__( s e l f , o b j , o b j t y p e ) : p r i n t ’ R e t r i e v i n g ’ , s e l f . name r e t u r n s e l f . v a l

d e f __set__ ( s e l f , o b j , v a l ) : p r i n t ’ U p d a t i n g ’ , s e l f . name s e l f . v a l = v a l

c l a s s B( o b j e c t ) :

x = R e v e a l A c c e s s ( 1 0 , ’ v a r ␣ " x " ’ ) y = 5

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 23 / 26

(27)

Deskryptory c.d.

Deskryptory pozwalają na łatwą realizację kapsułkowania.

property(fget=None, fset=None, fdel=None, doc=None)

c l a s s C( o b j e c t ) : d e f g e t x ( s e l f ) :

r e t u r n s e l f . __x d e f s e t x ( s e l f , v a l u e ) :

s e l f . __x = v a l u e d e f d e l x ( s e l f ) :

d e l s e l f . __x

x = p r o p e r t y ( g e t x , s e t x , d e l x , " I ’m␣ t h e ␣ ’ x ’ ␣ p r o p e r t y . " )

(28)

Metody statyczne

Przy pomocy deskryptorów można zrealizować metody statyczne.

c l a s s s t a t i c m e t h o d( o b j e c t ) : d e f __init__ ( s e l f , f ) :

s e l f . f = f

d e f __get__( s e l f , o b j , o b j t y p e=None ) : r e t u r n s e l f . f

P. Daniluk(Wydział Fizyki) PO w. VIII Jesień 2016 25 / 26

(29)

... i klasowe

c l a s s c l a s s m e t h o d( o b j e c t ) : d e f __init__ ( s e l f , f ) :

s e l f . f = f

d e f __get__( s e l f , o b j , k l a s s=None ) : i f k l a s s i s None :

k l a s s = t y p e ( o b j ) d e f n e w f u n c ( ∗ a r g s ) :

r e t u r n s e l f . f ( k l a s s , ∗ a r g s ) r e t u r n n e w f u n c

Cytaty

Powiązane dokumenty

Metody statyczne powodują kłopoty przy dziedziczeniu, jeżeli atrybuty, do których się odnoszą są przysłonięte w podklasie... Metody statyczne

‘&lt;opis obiektu&gt;’, który jest użyteczny przy debugowaniu – wywoływana przez repr(object). object.__str__(self) zwraca “ładny” napis – wywoływana

Katalogi w strukturze plików serwisu odpowiadają klasom Elementy katalogów (pliki i podkatalogi) odpowiadają atrybutom Aplikacja jest autonomicznym serwerem webowym. Treść nie

Paradygmat obiektowy doskonale nadaje się do opisywania struktury i stanu dużych systemów.. Niestety takie systemy rzadko kiedy pozostają niezmienne

Funkcje i klasy dające możliwie prosty sposób wyrażania operacji na reprezentacjach przetwarzanych informacji..

Gwiezdne Wojny 1977 124 kolor Potężne Kaczory 1991 104 kolor Świat Wayne’a 1992 95 kolor.. Daniluk(Wydział Fizyki)

javax.sql.rowset.serial Provides utility classes to allow serializable mappings be- tween SQL types and data types in the Java programming language.. javax.sql.rowset.spi The

Wielodziedziczenie interfejsów: cechy charakterystyczne, zalety, przykłady zastosowania (języki).. Wady