[Python] Ottimizzazione codice

2008-04-27 Per discussione Leonardo
Salve a tutti.
Sono agli inizi con Python, sto imparando grazie a varie guide trovate
online, e sto iniziando ad addentrarmi nell'ottimizzazione del codice.
Ora, ho scritto questo piccolo programmino (con GUI in pyGTK) che
accetta dei numeri come input, ne calcola la media, e restituisce la
media, il numero maggiore immesso, il numero minore, il numero più
vicino alla media.
Ora, vorrei dei consigli su come ottimizzare il codice, magari
sostituendo qualche ciclo if con qualcosa di più performante o simili =D
posto il codice: (non insultatemi perchè non c'è nemmeno un commento o
una doc string xD)


import pygtk
pygtk.require('2.0')
import gtk

def Media(numeri):
divisore = len(numeri)
a = 0
for num in numeri:
a = a + float(num)
try:
media = float(a) / float(divisore)
return media
except:
return None

def DistanzaDallaMedia(numero, media):
numero = float(numero)
distanzamedia = abs(numero - media)
return distanzamedia

class Finestra:
def __init__(self):
self.win = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.win.set_title(Calcolo media aritmetica)
self.win.connect(destroy, self.esci)
self.win.connect(delete_event, self.delete_event)
self.win.set_default_size(400,300)
self.vbox = gtk.VBox(0,0)
self.label = gtk.Label(Inserisci qui sotto i numeri 
dei quali
vuoi fare la media, separati da spazi.)
self.entry = gtk.Entry(100)
self.button = gtk.Button(Esegui, gtk.STOCK_EXECUTE)
self.button.connect(clicked, self.CalcolaMedia)
self.risultato = gtk.Label(Clicca su esegui, qui 
comparira'
il risultato)
self.statistiche = gtk.Label(Clicca su esegui, qui
compariranno alcune statistiche)
self.vbox.pack_start(self.label)
self.vbox.pack_start(self.entry)
self.vbox.pack_start(self.button)
self.vbox.pack_start(self.risultato)
self.vbox.pack_end(self.statistiche)
self.win.add(self.vbox)
self.win.show_all()

def GetUserInput(self, widget):
UserInput = widget.get_text()
return UserInput

def OttieniNumeri(self):
UserInput = self.GetUserInput(self.entry)
import string
Numeri = string.split(UserInput)
Numeri = map(int, Numeri)
return Numeri

def CalcolaMedia(self, widget):
Numeri = self.OttieniNumeri()
MediaCalcolata = Media(Numeri)
if MediaCalcolata: 
self.risultato.set_text(La media calcolata 
equivale a   +
str(MediaCalcolata))
Statistiche = {}
for num in Numeri:
if 'maggiore' not in Statistiche.keys():
Statistiche['maggiore'] = num
Statistiche['minore'] = num
Statistiche['vicino_media'] = 
num
else:
if DistanzaDallaMedia(num, 
MediaCalcolata) 
DistanzaDallaMedia(Statistiche['vicino_media'], MediaCalcolata):

Statistiche['vicino_media'] = num
if num  
Statistiche['maggiore']:
Statistiche['maggiore'] 
= num
elif num  
Statistiche['minore']:
Statistiche['minore'] = 
num
self.StampaStatistiche(Statistiche)
else:
self.risultato.set_text(Devi inserire almeno 
un numero!)

def StampaStatistiche(self, Statistiche):
self.statistiche.set_text(Il numero maggiore inseirto 
e'  +
str(Statistiche['maggiore']) + \nIl numero minore inserito e' 
+ str(Statistiche['minore']) + \nIl numero inserito piu' vicino

Re: [Python] Ottimizzazione codice

2008-04-27 Per discussione Daniele Zambelli
Alle domenica 27 aprile 2008, Leonardo ha scritto:
 Salve a tutti.
 Sono agli inizi con Python, sto imparando grazie a varie guide trovate
 online, e sto iniziando ad addentrarmi nell'ottimizzazione del codice.

Benvenuto

 Ora, ho scritto questo piccolo programmino (con GUI in pyGTK) che
 accetta dei numeri come input, ne calcola la media, e restituisce la
 media, il numero maggiore immesso, il numero minore, il numero più
 vicino alla media.

Sei partito da un problema classico che dà diversi spunti di riflessione. È 
interessante la combinazione tra l'interfaccia grafica e gli algoritmi di 
elaborazione dati.

 Ora, vorrei dei consigli su come ottimizzare il codice, magari
 sostituendo qualche ciclo if con qualcosa di più performante o simili =D
 posto il codice: (non insultatemi perchè non c'è nemmeno un commento o
 una doc string xD)

Qualche commento ci sta bene, di solito, ma hai usato nomi delle funzioni 
sufficientemente esplicativi e quindi il tuo codice è chiaro.

Non ho le gtk e non ho il tempo di provare il codice che posto, per cui prendi 
le cose che scrivo come degli spunti per approfondire.
Altro avvertimento, in lista ci sono molti programmatori più competenti di 
me... fa la tara a quello che scrivo.

1. ottimizzazione: Di solito è buona norma preoccuparsi delle performances di 
un programa più avanti... comunque ridurre le righe di codice va nella 
direzione di rendere il programma più semplice e di solito più efficiente.



 import pygtk
 pygtk.require('2.0')
 import gtk

 def Media(numeri):
   divisore = len(numeri)
   a = 0
   for num in numeri:
   a = a + float(num)
   try:
   media = float(a) / float(divisore)
   return media
   except:
   return None

2. a lo chiamerei somma, numeri contiene già dei numeri, non c'è motivo per 
cui la divisione non possa funzionare a ameno che la lista sia vuota.
Quindi la funzione potrebbe diventare:

 def Media(numeri):
   if not numeri:
   return None
   somma = 0
   for num in numeri:
   somma += num
   return float(somma) / len(numeri)

tenendo presente che Python è in grado di sommare gli elementi di una lista la 
funzione si può semplificare ulteriormente usando la funzione sum(lista).

 def DistanzaDallaMedia(numero, media):
   numero = float(numero)
   distanzamedia = abs(numero - media)
   return distanzamedia

3. Anche qui le cose si possono semplificare:

 def DistanzaDallaMedia(numero, media):
   return abs(numero - media)

 class Finestra:
   def __init__(self):
   self.win = gtk.Window(gtk.WINDOW_TOPLEVEL)
   self.win.set_title(Calcolo media aritmetica)
   self.win.connect(destroy, self.esci)
   self.win.connect(delete_event, self.delete_event)
   self.win.set_default_size(400,300)
   self.vbox = gtk.VBox(0,0)
   self.label = gtk.Label(Inserisci qui sotto i numeri 
 dei quali
 vuoi fare la media, separati da spazi.)
   self.entry = gtk.Entry(100)
   self.button = gtk.Button(Esegui, gtk.STOCK_EXECUTE)
   self.button.connect(clicked, self.CalcolaMedia)
   self.risultato = gtk.Label(Clicca su esegui, qui 
 comparira'
 il risultato)
   self.statistiche = gtk.Label(Clicca su esegui, qui
 compariranno alcune statistiche)
   self.vbox.pack_start(self.label)
   self.vbox.pack_start(self.entry)
   self.vbox.pack_start(self.button)
   self.vbox.pack_start(self.risultato)
   self.vbox.pack_end(self.statistiche)
   self.win.add(self.vbox)
   self.win.show_all()

   def GetUserInput(self, widget):
   UserInput = widget.get_text()
   return UserInput

   def OttieniNumeri(self):
   UserInput = self.GetUserInput(self.entry)
   import string
   Numeri = string.split(UserInput)
   Numeri = map(int, Numeri)
   return Numeri

4. Per la maggior parte dei compiti non è necessario importare string, 
utilizzando le funzioni in cascata si possono evitare le variabili:

   def OttieniNumeri(self):
   return map(int, self.GetUserInput(self.entry).split())


   def CalcolaMedia(self, widget):
   Numeri = self.OttieniNumeri()
   MediaCalcolata = Media(Numeri)