Programowanie i projektowanie obiektowe

Transkrypt

Programowanie i projektowanie obiektowe
Programowanie i projektowanie obiektowe
Python od środka
Paweł Daniluk
Wydział Fizyki
Jesień 2014
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
1 / 48
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. XII
Jesień 2014
2 / 48
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ą.
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
3 / 48
Zasięgi – przykłady
def f ( ) :
print (x)
x = ’ global ’
f ()
def f ( ) :
x = ’f ’
print (x)
x = ’ global ’
print (x)
f ()
print (x)
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
4 / 48
Zasięgi – przykłady
def f ( ) :
print (x)
x = ’f ’
x = ’ global ’
f ()
def f ( ) :
print (x)
def g ( ) :
global x
print (x)
x = ’g ’
x = ’ global ’
f ()
g ()
f ()
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
5 / 48
Zasięgi – przykłady
x = ’ global ’
def f ( ) :
def g ( ) :
global x
print (x)
x = ’f ’
g ()
f ()
def f ( ) :
def g ( ) :
nonlocal x
x = ’g ’
x = ’f ’
g ()
print (x)
x = ’ global ’
f ()
print (x)
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
6 / 48
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.
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
7 / 48
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. XII
Jesień 2014
8 / 48
Typy wbudowane w Pythona
None
NotImplemented
Ellipsis
numbers.Number
I
I
I
numbers.Integral
numbers.Real
numbers.Complex
Sequences
I
immutable
F
F
F
I
strings
unicode
tuples
mutable
F
F
lists
byte arrays
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
9 / 48
Typy wbudowane w Pythona
sets
I
I
set
frozenset
mappings
callable types
I
I
I
I
I
I
I
I
user-defined functions
user-defined methods
generator functions
built-in functions
built-in methods
class types (new-style)
classic classes
class instances (czasem)
modules
classes
class instances
files
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
10 / 48
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
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
11 / 48
Funkcje są obiektami
Funkcje nazwane
def f ( x ) :
r e t u r n x+1
Funkcje anonimowe
f=lambda x : x+1
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
12 / 48
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.
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
13 / 48
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. XII
Jesień 2014
14 / 48
Nowe i stare klasy (new-style classes, classic classes)
New-style classes
Classic classes
Włączone w system typów.
Niezależne od systemu
typów.
Typ instancji jest równy jej
klasie.
Instancje klas są typu
<type ’instance’>.
Dziedziczą z klasy object.
Możliwości klas w nowym stylu
metody statyczne i klasowe
cechy i deskryptory
lepsze wielodziedziczenie
metaklasy
__slots__
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
15 / 48
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).
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
16 / 48
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. XII
Jesień 2014
16 / 48
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. XII
Jesień 2014
17 / 48
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 )
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
18 / 48
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. XII
Jesień 2014
18 / 48
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 )
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
19 / 48
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. XII
Jesień 2014
19 / 48
Strategia następnej metody
c l a s s A( o b j e c t
d e f m( s e l f
c l a s s B(A ) :
d e f m( s e l f
c l a s s C(A ) :
d e f m( s e l f
c l a s s D(B , C ) :
d e f m( s e l f
A .__mro__
B .__mro__
C .__mro__
D .__mro__
==
==
==
==
):
) : " s a v e ␣A ’ s ␣ d a t a "
) : " s a v e ␣B ’ s ␣ d a t a " ; s u p e r (B , s e l f ) .m( ) # C
) : " s a v e ␣C ’ s ␣ d a t a " ; s u p e r (C , s e l f ) .m( ) # A
) : " s a v e ␣D ’ s ␣ d a t a " ; s u p e r (D, s e l f ) .m( ) # B
(A ,
(B ,
(C ,
(D,
object )
A, object )
A, object )
B, C, A, object )
super(class, obj)
nie musi być nadklasą class
jest nadklasą obj.__class__
obj musi być instancją pewnej podklasy class
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
20 / 48
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. XII
Jesień 2014
21 / 48
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 ) :
def f1 ( s e l f ) :
p r i n t " Jestem ␣ f 1 "
def f2 ( s e l f ) :
p r i n t " Jestem ␣ f 2 "
def 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 )
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
22 / 48
Deskryptory
Obiekt implementujący co najmniej jedną z metod __get__(), __set()__,
__delete()__ nazywa się deskryptorem.
class RevealAccess ( object ) :
d e f __init__ ( s e l f , i n i t v a l =None , name= ’ v a r ’ ) :
s e l f . val = 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
return s e l f . val
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 . val = val
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 (10 , ’ var ␣"x" ’ )
y = 5
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
23 / 48
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 ) :
def getx ( s e l f ) :
r e t u r n s e l f . __x
def setx ( s e l f , value ) :
s e l f . __x = v a l u e
def delx ( 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 . " )
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
24 / 48
Metody statyczne
Przy pomocy deskryptorów można zrealizować metody statyczne.
c l a s s staticmethod ( object ) :
d e f __init__ ( s e l f , f ) :
self . f = f
d e f __get__( s e l f , o b j , o b j t y p e=None ) :
return s e l f . f
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
25 / 48
... i klasowe
c l a s s classmethod ( object ) :
d e f __init__ ( s e l f , f ) :
self . 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 = type ( obj )
d e f ne wfun c ( ∗ a r g s ) :
return s e l f . f ( klass , ∗ args )
r e t u r n ne wfunc
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
26 / 48
@dekoratory
Metody statyczne (i klasowe) można tworzyć korzystając z klas
staticmethod i classmethod.
c l a s s A( o b j e c t ) :
def f ( ) :
pass
s t a t i c =s t a t i c m e t h o d ( f )
def g( c l s ) :
pass
g=c l a s s m e t h o d ( g )
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
27 / 48
@dekoratory c.d.
Ale zazwyczaj stosuje się zapożyczoną z Javy składnię.
c l a s s A( o b j e c t ) :
@staticmethod
def f ( ) :
pass
@classmethod
def g ( c l s ) :
pass
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
28 / 48
@dekoratory c.d.
Napis:
@dekorator
def f ( arg ) :
...
oznacza:
def f ( arg ) :
...
f=d e k o r a t o r ( f )
Dekorator funkcji jest funkcją, która jako argument bierze funkcję
dekorowaną i zwraca zmodyfikowaną funkcję.
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
29 / 48
@dekoratory c.d.
Przykład
def bread ( func ) :
def wrapper ( ) :
p r i n t " </ ’ ’ ’ ’ ’ ’\ > "
func ()
p r i n t "<\______/>"
r e t u r n wrapper
def i n g r e d i e n t s ( func ) :
def wrapper ( ) :
p r i n t "#t o m a t o e s#"
func ()
p r i n t "~ s a l a d ~"
r e t u r n wrapper
d e f s a n d w i c h ( f o o d="−−ham−−" ) :
p r i n t food
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
30 / 48
@dekoratory c.d.
Przykład
sandwich ()
#o u t p u t s : −−ham−−
sandwich = bread ( i n g r e d i e n t s ( sandwich ))
sandwich ()
#o u t p u t s :
#</ ’ ’ ’ ’ ’ ’\ >
# #t o m a t o e s#
# −−ham−−
# ~salad~
#<\______/>
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
31 / 48
@dekoratory c.d.
@bread
@ingredients
d e f s a n d w i c h ( f o o d="−−ham−−" ) :
p r i n t food
sandwich ()
#o u t p u t s :
#</ ’ ’ ’ ’ ’ ’\ >
# #t o m a t o e s#
# −−ham−−
# ~salad~
#<\______/>
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
32 / 48
@dekoratory c.d.
Kolejność ma znaczenie
@ingredients
@bread
d e f s t r a n g e _ s a n d w i c h ( f o o d="−−ham−−" ) :
p r i n t food
strange_sandwich ()
#o u t p u t s :
##t o m a t o e s#
#</ ’ ’ ’ ’ ’ ’\ >
# −−ham−−
#<\______/>
# ~salad~
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
33 / 48
@dekoratory – przekazywanie argumentów
def a_decorator_passing_arguments ( function_to_decorate ) :
d e f a _ w r a p p e r _ a c c e p t i n g _ a r g u m e n t s ( arg1 , a r g 2 ) :
p r i n t " I ␣ g o t ␣ a r g s ! ␣ Look : " , arg1 , a r g 2
f u n c t i o n _ t o _ d e c o r a t e ( arg1 , a r g 2 )
r e t u r n a_wrapper_accepting_arguments
@a_decorator_passing_arguments
d e f p r i n t _ f u l l _ n a m e ( f i r s t _ n a m e , last_name ) :
p r i n t "My␣name␣ i s " , f i r s t _ n a m e , last_name
p r i n t _ f u l l _ n a m e ( " P e t e r " , "Venkman" )
# outputs :
#I g o t a r g s ! Look : P e t e r Venkman
#My name i s P e t e r Venkman
Przy dekoratorach stosowanych do dowolnych funkcji używa się
*args, **kwargs.
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
34 / 48
@dekoratory – przekazywanie argumentów do dekoratora
d e f wrap_in_tag ( t a g ) :
def f a c t o r y ( func ) :
d e f d e c o r a t o r ( ∗ a r g s , ∗∗ k w a r g s ) :
r e t u r n ’<%(t a g ) s>%(r v ) s </%(t a g ) s> ’ %
( { ’ t a g ’ : tag , ’ r v ’ : f u n c ( ∗ a r g s , ∗∗ k w a r g s ) } )
return decorator
return factory
@wrap_in_tag ( ’ b ’ )
@wrap_in_tag ( ’ i ’ )
def say ( v a l ) :
return val
p r i n t say ( ’ h e l l o ’ )
Funkcja wrap_in_tag zwraca dekorator, który dokłada do wyniku
dekorowanej funkcji zadany tag XML.
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
35 / 48
Klasy również można dekorować
d e f addID ( o r i g i n a l _ c l a s s ) :
o r i g _ i n i t = o r i g i n a l _ c l a s s . __init__
d e f __init__ ( s e l f , i d , ∗ a r g s , ∗∗ kws ) :
s e l f . __id = i d
s e l f . getId = getId
o r i g _ i n i t ( s e l f , ∗ a r g s , ∗∗ kws )
o r i g i n a l _ c l a s s . __init__ = __init__
return original_class
@addID
c l a s s Foo :
pass
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
36 / 48
Konstruktory i inicjalizatory
Metoda __new__
__new__ jest metodą statyczną, która jako pierwszy argument bierze klasę
obiektu, który ma zostać stworzony. Pozostałe argumenty są przekazywane
do inicjalizatora.
Metoda __init__
__init__ jest wywoływana po __new__.
Metoda __call__
Tworząc klasę (np. A()) wywołujemy metodę __call__, która wywołuje
po kolei __new__ i __init__.
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
37 / 48
Konstruktory i inicjalizatory - c.d.
Przykład
c l a s s A( o b j e c t ) :
d e f __init__ ( s e l f ) :
self .x = 1
In
[1]:
...:
...:
...:
In
[ 2 ] : a1 = A ( )
I n [ 3 ] : a1 . x
Out [ 3 ] : 1
In
[ 4 ] : a2 = A .__new__(A)
I n [ 5 ] : a2
Out [ 5 ] : <__main__ . A a t 0 x10434b750>
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
38 / 48
Konstruktory i inicjalizatory - c.d.
Przykład
I n [ 6 ] : a2 . x
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
AttributeError
T r a c e b a c k ( most r e c e n t c a l l l a s t )
<i p y t h o n −i n p u t −6−e c e f 1 d 0 4 6 d 2 3 > i n <module >()
−−−−> 1 a2 . x
AttributeError :
In
’A ’ o b j e c t h a s no a t t r i b u t e
’x ’
[ 7 ] : a2 . __init__ ( )
I n [ 8 ] : a2 . x
Out [ 8 ] : 1
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
39 / 48
Metoda __new__
c l a s s GimmeFive ( o b j e c t ) :
d e f __new__( c l s , ∗ a r g s , ∗∗ k w a r g s ) :
return 5
Zastosowania
1
Tworzenie obiektu innej klasy.
2
Wykonanie operacji, które nie mogą zależeć od implementacji
__init__ w podklasach.
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
40 / 48
Metoda __new__ - przykład
c l a s s Operator ( object ) :
d e f __new__( c l s , op , ∗ a r g s , ∗∗ k w a r g s ) :
i f op == ’+ ’ :
r e t u r n s u p e r ( O p e r a t o r , c l s ) . __new__( Add )
e l i f op == ’ ∗ ’ :
r e t u r n s u p e r ( O p e r a t o r , c l s ) . __new__( Mul )
d e f __init__ ( s e l f , op , arg1 , a r g 2 ) :
s e l f . arg1 = arg1
s e l f . arg2 = arg2
c l a s s Add ( O p e r a t o r ) :
def eval ( s e l f ) :
return s e l f . arg1 + s e l f . arg2
c l a s s Mul ( O p e r a t o r ) :
def eval ( s e l f ) :
return s e l f . arg1 ∗ s e l f . arg2
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
41 / 48
Metoda __new__ - przykład
I n [ 2 ] : op . O p e r a t o r ( ’+ ’ , 3 , 4 )
Out [ 2 ] : <op . Add a t 0 x1071a5790>
I n [ 3 ] : op . O p e r a t o r ( ’+ ’ , 3 , 4 ) . e v a l
Out [ 3 ] : <bound method Add . e v a l o f <op . Add o b j e c t a t 0 x1071a5b90>
I n [ 4 ] : op . O p e r a t o r ( ’+ ’ , 3 , 4 ) . e v a l ( )
Out [ 4 ] : 7
I n [ 5 ] : op . O p e r a t o r ( ’ ∗ ’ , 3 , 4 ) . e v a l ( )
Out [ 5 ] : 12
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
42 / 48
Metaklasy
(Lasciate ogni speranza)
Klasy są obiektami:
klasy type – new-style classes
klasy types.ClassType – classic classes
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
43 / 48
Metaklasy
(Lasciate ogni speranza)
Klasy są obiektami:
klasy type – new-style classes
klasy types.ClassType – classic classes
W zasadzie nic nie stoi na przeszkodzie, aby klasy były obiektami dowolnej
klasy (metaklasy).
Jaki jest z tego pożytek?
sianie zamętu i zniechęcenia
kontrola tworzenia klasy (metody __new__ i __init__)
kontrola tworzenia obiektów klasy (metoda __call__)
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
43 / 48
Metaklasy c.d.
Metaklasa danej klasy jest określona przez:
atrybut __metaclass__
metaklasa jednej z klas bazowych
zmienna globalna __metaclass__
types.ClassType
Tworzenie klasy skutkuje wywołaniem metaklasy:
M( name , b a s e s , d i c t )
gdzie:
name – nazwa klasy
bases – klasy bazowe
dict – elementy klasy
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
44 / 48
Metaklasy c.d.
c l a s s Meta ( t y p e ) :
d e f __init__ ( c l s , name , b a s e s , d i c t ) :
p r i n t " Definiowana ␣ klasa : " , c l s
p r i n t " o ␣ n a z w i e : ␣ " , name
p r i n t " d z i e d z i c z y ␣ z : ␣" , b a s e s
p r i n t "o␣ elementach : ␣" , d i c t
t y p e . __init__ ( c l s , name , b a s e s , d i c t )
d e f __call__ ( c l s , ∗ a r g s , ∗∗ k w a r g s ) :
p r i n t " Tworze ␣ o b i e k t ␣ k l a s y : " , c l s
r e t u r n t y p e . __call__ ( c l s , ∗ a r g s , ∗∗ k w a r g s )
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
45 / 48
Metaklasy c.d.
I n [ 1 0 ] : c l a s s A( o b j e c t ) :
....:
__metaclass__ = Meta
....:
d e f m( s e l f ) :
....:
p r i n t " J e s t e m ␣m"
....:
D e f i n i o w a n a k l a s a : < c l a s s ’__main__ . A ’>
o nazwie : A
d z i e d z i c z y z : (< t y p e ’ o b j e c t ’ > ,)
o e l e m e n t a c h : { ’m ’ : <f u n c t i o n m a t 0 x 1 0 e 3 c 0 d e 8 >, ’__module__ ’ :
In [ 1 1 ] : A( )
Tworze o b i e k t k l a s y : < c l a s s ’__main__ . A ’>
Out [ 1 1 ] : <__main__ . A a t 0 x10e3b8e50 >
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
46 / 48
Metaklasy c.d.
Przykład – automatyczne tworzenie properties
c l a s s autoprop ( type ) :
d e f __init__ ( c l s , name , b a s e s , d i c t ) :
s u p e r ( a u t o p r o p , c l s ) . __init__ ( name , b a s e s , d i c t )
p r o p s = {}
f o r member i n d i c t . k e y s ( ) :
i f member . s t a r t s w i t h ( "_get_" )
o r member . s t a r t s w i t h ( "_set_" ) :
p r o p s [ member [ 5 : ] ] = 1
f o r prop i n props . keys ( ) :
f g e t = g e t a t t r ( c l s , "_get_%s " % prop , None )
f s e t = g e t a t t r ( c l s , "_set_%s " % prop , None )
s e t a t t r ( c l s , prop , p r o p e r t y ( f g e t , f s e t ) )
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
47 / 48
Metaklasy c.d.
Zastosowanie
I n [ 2 9 ] : c l a s s A( o b j e c t ) :
....:
__metaclass__ = a u t o p r o p
....:
d e f _get_x ( s e l f ) :
....:
p r i n t "_get_x"
....:
r e t u r n a . __x
....:
d e f _set_x ( s e l f , x ) :
....:
p r i n t " _set_x "
....:
s e l f . __x = x
....:
In [ 3 0 ] : a = A( )
In [ 3 1 ] : a . x = 5
set_x
In [ 3 2 ] : a . x
get_x
get_x
Out [ 3 2 ] : 5
P. Daniluk(Wydział Fizyki)
PO w. XII
Jesień 2014
48 / 48