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