Python è un elegante linguaggio di programmazione. Forse è quello che preferisco dal punto di vista estetico (ti costringe a scrivere bene, cioè a produrre codice bello da vedere oppure non funziona affatto). Nonostante questa mia preferenza lo uso di rado.
Sommario
Indice
Tutorial vero
Vedi quello di Van Rossum [in italiano].
Tutorial di legno
Ora il mio
scrivere questo file myClass.py:
class MyClass:
"""A simple example class"""
i = 12345
def __init__(self):
self.data = []
def f(self):
return 'hello world'
Poi aprire un shell e invocare l’interprete python
$ python Python 2.7.3 (default, Aug 1 2012, 05:14:39) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>>
Ora importiamo la classe MyClass così:
>>> from myClass import MyClass >>>
Verifichiamo che sia stata caricata:
>>> MyClass <class myClass.MyClass at 0x7fa841640120>
Se scrivo il nome del file anziché il nome della classe, non funzionerà:
>>> myClass Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'myClass' is not defined
cosa c’è dentro la classe?
>>> dir(MyClass) ['__doc__', '__init__', '__module__', 'f', 'i']
Inizializziamo un oggetto della classe MyClass:
>>> x = MyClass()
e che cosa fa questa classe?
>>> x.__doc__ 'A simple example class'
Adesso possiamo provare metodi e attributi
>>> x.i 12345 >>> x.f() 'hello world' >>>
E’ tutto per ora!
Esercizi per casa
- Costruire una classe che gestisce i numeri complessi
- Costruire una classe che gestisce una rubrica telefonica (cablare pure i dati nel codice)
Numeri complessi
Al primo tentativo questo è il costruttore (file Complessi.py)
class Complessi:
"""Wrapper per numeri complessi: la classe Complex c'e' gie', ne faccio una di nuova
che utilizza quella esistente interponendosi (concetto di wrapping) """
def __init__(self):
self.__repr__ = self.partition('+')
self.re = self.__repr__[0]
self.im = self.__repr__[1]
provo la classe
>>> from Complessi import Complessi
>>> x=Complessi('1+2j')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __init__() takes exactly 1 argument (2 given)
>>>
Uno sguardo alla guida di Van Rossum che ha guarda caso lo stesso esempio; riprovo così:
class Complessi:
"""Wrapper per numeri complessi: la classe Complex c'e' gia', ne faccio una di nuova
che utilizza quella esistente interponendosi (concetto di wrapping) """
def __init__(self, re, im):
self.re = re
self.im = im
la provo
>>> x=Complessi(1,2) >>> x <Complessi.Complessi instance at 0x7f0b6797d050> >>> x.re 1 >>> x.im 2 >>>
l’output non è soddisfacente. Ulteriore metodo per stampare un numero complesso
def view(self):
if (self.im < 0):
self.sign = '-j';
else:
self.sign = '+j';
self.__out__ = str(self.re) + self.sign + str(abs(self.im))
return self.__out__
Questo è il risultato:
>>> x=Complessi(1,-2) >>> x.view() '1-j2'
Overloading degli operatori
Ora mi sono sbizzarrito a creare nuovi metodi ed ho anche imparato a fare l’ overloading degli operatori. Ciò significa che posso riutilizzare il + per fare la somma tra numeri complessi. Ad esempio ecco come realizzare l’overloading della somma:
def __add__(self, a):
re = self.re + a.re
im = self.im + a.im
return Complessi(re,im)
la parolina magica __add__ è quella che fa tutto. Il codice parla da se.
Osservazione importante
Attenzione si potrebbe anche implementare la funzione così:
def __add__(self, a):
self.re = self.re + a.re
self.im = self.im + a.im
return self
In questo caso non c’è alcun errore di sintassi ma l’effetto è perverso: eseguendo l’istruzione
w = x + y
il risultato sarà sì corretto ma avremo lo spiacevole effetto collaterale di alterare anche il valore della x che è il primo parametro!
Già che ci siamo eliminiamo il metodo customizzato view e facciamo l’overload della funzione __str__ che è quella che ci permette di stampare una variabile con l’istruzione print:
def __str__(self): # personalizza la funzione print if (self.im < 0): self.sign = '-j'; else: self.sign = '+j';
Testare il codice
Ultima cosa: come fare il test degli scipt python? esiste lo Unit test e il Doc test. Prima quest’ultimo
Doctest
Scrivo un file python in cui definisco una funzione e il suo test viene scritto nei commenti:
#!/usr/bin/python
"""
>>> print x # numero complesso 1-j2
1-j2
>>> x.reale()
1
>>> x.immaginario()
-2
>>> print y # numero complesso 1+j1
1+j1
>>> print w # somma
2-j1
>>> print v # prodotto
3-j1
"""
from Complessi import Complessi
x = Complessi(1,-2)
y = Complessi(1,1)
w = x + y
v = x * y
if __name__ == "__main__":
import doctest
doctest.testmod()
Ecco qui eseguo le operazioni con gli oggetti della classe da testare e alla fine metto l’invocazione della classe doctest: in sostanza i test da fare li scrivo nel commento!!! Proviamolo, nella documentazione scrivo sia l’operazione da compiere sia il valore atteso:
#!/usr/bin/python
"""
>>> print x # numero complesso 1-j2 <--- qui metto il test da eseguire; la variabile è inizializzata nel codice vero
1-j2 <--- qui metto il risultato che il software mi dovrebbe dare (lo calcolo a mano)
>>> x.reale()
1
>>> x.immaginario()
-2
>>> print y # numero complesso 1+j1
1+j1
>>> print w # somma
2-j1
>>> print v # prodotto
3-j1
"""
from Complessi import Complessi
x = Complessi(1,-2)
y = Complessi(1,1)
w = x + y
v = x * y
if __name__ == "__main__":
import doctest
doctest.testmod()
nota bene: mettendo in alto la dichiarazione dell’interprete #!/usr/bin/python, da linea di comando è sufficiente scrivere ./testdoc1.py -v (occorre anche dichiarare eseguibile il file per cui da shell Linux occorre prima lanciare il comando chmod a+x testdoc1.py Ecco l’esecuzione:
$ ./testdoc1.py -v
Trying:
print x # numero complesso 1-j2
Expecting:
1-j2
ok
Trying:
x.reale()
Expecting:
1
ok
Trying:
x.immaginario()
Expecting:
-2
ok
Trying:
print y # numero complesso 1+j1
Expecting:
1+j1
ok
Trying:
print w # somma
Expecting:
2-j1
ok
Trying:
print v # prodotto
Expecting:
3-j1
ok
1 items passed all tests:
6 tests in __main__
6 tests in 1 items.
6 passed and 0 failed.
Test passed.
Risorse web
[1] Doctest sul sito python.org
Commenti recenti