Torna a Howto

Python

Spread the love

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.

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

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.