Python, il cui nome deriva da un famoso programma della BBC "Monty Python's Flying Circus'', è la creazione di Guido van Rossum dello Stichting Mathematisch Centrum (Olanda), come evoluzione di un linguaggio chiamato ABC, agli inizi del 1990. Van Rossum ne è il principale autore, ma il progetto si avvale ora di numerosi contributori.
Python è un linguaggio di programmazione facile da imparare e, poiché è un linguaggio interpretato, è semplice e piacevole da utilizzare. E' dotato di un'efficiente struttura di dati di alto livello ed un efficace approccio alla programmazione object-oriented. È ideale come linguaggio di scripting o per lo sviluppo rapido di applicazioni. Python è disponibile in molte piattaforme.
L'interprete di Python è estendibile tramite funzioni o tipi di dato scritti in C o C++; si presta anche ad essere integrato in applicazioni per fornirle di programmabilità.
E' corredato di diverse librerie, fra cui librerie
per le funzioni di I/O, per il WEB, per la crittografia, per l'elaborazione
parallela e per interfacce grafiche. Di queste ve ne sono parecchie, quelle
"più ufficiali" sono: Tkinter, un'interfaccia al toolkit Tk
GUI, Tix un'estensione di Tk e turtle che implementa una
tartaruga tipo LOGO, utilizzando Tk (Tk è stato scritto con il linguaggio TCL).
I programmi, grazie alla
tipizzazione dinamica dei dati, all'utilizzo dell'indentazione per la
costruzione dei blocchi di istruzioni e alla non necessità di dichiarare le
variabili, sono compatti e leggibili.
L'interattività di Python ne fa una calcolatrice
efficace (>>> è
il prompt di Python):
>>>
altezza = 10.5
>>>
larghezza = 20
>>>
peso = 20
>>>
'peso specifico', larghezza*altezza/peso
('peso specifico', 10.5)
Fra i tipi di dato si hanno:
§ Oggetti. Dopo averli dichiarati vanno istanziati. Nell'esempio che segue possiamo pensare l'oggetto Coord come un punto generico nel piano, mentre w e z sono due punti particolari. La funzione dist utilizza gli oggetti Coord per calcolare la distanza di due punti nel piano.
>>> class Coord:
def
__init__(self, ordinata, ascissa):
self.x
= ordinata
self.y = ascissa
>>> w=Coord(0,0)
>>> z=Coord(3,4)
>>> def dist(p1,p2):
return
pow(pow((p1.x-p2.x),2)+pow((p1.y-p2.y),2),0.5)
>>> dist(w,z)
5.0
§ Numeri immaginari:
>>>
imgr=(1.5 + 0.7J) + complex(2,3.3)
>>> imgr,imgr.real,imgr.imag
((3.5+4j), 3.5, 4.0)
§ Tuple: insiemi di dati separati da virgola, ed eventualmente racchiusi fra parentesi tonde, imgr, imgr.real, imgr.imag del punto precedente è una tupla. Le tuple, come del resto le stringhe di caratteri, non sono direttamente modificabili.
§ Liste o sequenze, con un'insieme di metodi e funzioni che le rendono maneggevoli ed atte a realizzare code o stack:
>>>
coda = ["Carla", "Enrico", "Michele"]
>>>
coda.append("Teresa")
>>>
coda.pop(0)
'Carla'
>>>
coda
['Enrico', 'Michele',
'Teresa']
La funzione range(from, to, step) genera una lista di numeri.
§ Matrici: insiemi omogenei di valori. Sono implementate come oggetti:
>>> import array
# libreria che implementa gli array
>>> mat = array.array('c','array di caratteri')
>>> mat
array('c',
'array di caratteri')
§ Dizionari: ogni elemento è individuato da una chiave, che è il mezzo per accedere al suo valore. Il valore può essere un qualsiasi dato o oggetto di Phyton:
>>>
diz = {'imgr': imgr, 'coda': coda,'matrice': mat}
>>>
diz['tupla']= 3.1415,'pigreco mezzi' # aggiungo una voce
>>>
diz['matrice']
array('c', 'array di caratteri')
Esistono
funzioni su funzioni: filter(), map(), e reduce(); sono molto efficaci quando
utilizzate con liste: filter(funzione, sequenza) genera una sequenza con i soli
elementi di sequenza per i quali la funzione (unaria) funzione(sequenza[indice]) è vera.
map(funzione, sequenza) genera una sequenza con i
valori di funzione(sequenza[indice]). Ad esempio:
>>>
def media(x,y): return(x+y)/2
>>> seq = range(8)
>>> seq
[0, 1, 2, 3, 4, 5, 6, 7]
>>>
map(media,seq,range(8,24,2))
[4, 5, 7, 8, 10, 11, 13,
14]
reduce(funzione, sequenza) calcola la funzione (binaria) funzione, applicata ai primi due
elementi della sequenza, successivamente applica funzione al risultato ed al terzo elemento, e così via fino ad
esaurire la sequenza.
Nell’esempio che segue Python è utilizzato per simulare un
servente di disco che cerca di minimizzare gli spostamenti della testina
magnetica. Le richieste sono generate da task concorrenti. Una visualizzazione
dei risultati è ottenuta con Liberty Basic (v. par. 2.7).
# Python 2.2b2 (#26, Nov 16 2001, 11:44:11) [MSC 32
bit (Intel)] on win32
#
# Simulazione di un
servente di disco.
# Le richieste sono accodate in una coda FIFO,
tuttavia se nel tragitto dalla traccia
# attuale a quella voluta, c'è una richiesta,
questa è soddisfatta
# --- accesso alle
funzioni utilizzate
from time import sleep, gmtime, strftime, clock
from threading import * # concorrenzialità
from random import random,choice
req = [] # coda delle
richieste di servizio contiene un progressivo usato
# come chiave del
dizionario d_req i cui elementi sono una lista
# con le caratteristiche del servizio richiesto
n_req = 0 # progressivo richieste
d_req ={} # db delle richieste
n_task = 10 # numero task clienti
sema_req =
BoundedSemaphore() # semaforo per
aggiornare l'array delle richieste
sema_log =
BoundedSemaphore() # semaforo per
serializzare il log
StatoServente = Event() # oggetto Evento per controllare il servente
# genero gli eventi
associati ai task per segnalare la fine del servizio
for i in range(1,n_task+1):
exec
('Cliente' + str(i) + ' = Event()')
fl = open('log.txt','w')
clock_in =
clock() # prelevo inizio
clock
def logga(*args):
sema_log.acquire()
fl.write('%6.2f' %
(clock() - clock_in))
for x in
args:
fl.write(' ' + x)
print ' ',x,
fl.write('\n')
print
sema_log.release()
def simula():
logga('----- Inizio simulazione -----')
global n_req, req,
d_req
tServer =
Thread(group=None,target=servente,name='Servente')
tServer.start()
tServer.run
for i in
range(1,n_task+1):
nome_task =
't' + str(i)
args =
str(1.0*random()) + ',\'Cliente' + str(i) + '\',' + str(choice(range(5,15)))
exec(nome_task + ' = Thread(target=task,args=(' + args + '))')
exec(nome_task + '.start()')
exec(nome_task
+ '.run')
while
activeCount() > 2: pass # attendo fine dei threads
StatoServente.set() # Servente inattivo
def
task(tempo=1,cliente='anonimo',volte = 3):
# tempo: intervallo medio di richiesta servizio
# cliente: nome del richiedente
# volte: numero richieste
logga('- Partenza di:', cliente,'-')
logga(' intervallo medio
richieste: %6.3f Numero richieste: %3d'
% (tempo,volte))
for i in
range(0,volte):
trk_req =
choice(range(1,1001))
blk_req =
choice(range(1,6))
richiesta_servizio(cliente,trk_req,blk_req)
init_time = clock()
exec(cliente + '.clear()')
exec(cliente + '.wait()')
logga('',cliente,' traccia:',str(trk_req),' t. risp.',('%5.3f' %
(clock()-init_time)))
sleep(2.0
* tempo * random())
logga('Fine
di:', cliente)
def
richiesta_servizio(cliente,traccia,durata):
global n_req, req, d_req
# accodo la richiesta e creo voce dizionario
sema_req.acquire()
n_req = n_req + 1
req.append(n_req)
d_req[n_req] = [cliente,traccia, durata]
sema_req.release()
def servente():
global req, d_req
logga('--- Partenza Servente ---')
s_req = [] #
lista serviti
trk = 0 # 0 =
posizione iniziale
t_trk = 0.002 #
tempo per spostarsi di 1 traccia
t_blk = 0.0005 #
tempo di lettura settore
while not
StatoServente.isSet():
if len(req)
> 0:
sema_req.acquire()
# blocco l'aggiornamento delle richieste
logga('Coda in:',repr(req))
trk_serv = d_req[req[0]][1]
# traccia richiesta
indx = 0 # indice della richiesta
for i in
range(1,len(req)):
if
trk_serv > trk:
if
d_req[req[i]][1] > trk and d_req[req[i]][1] < trk_serv:
indx
= i
break
# esce al primo trovato
else:
if
d_req[req[i]][1] > trk_serv and d_req[req[i]][1] < trk:
indx
= i
break
# esce al primo trovato
trk_serv = d_req[req[indx]][1] # traccia richiesta
cliente = d_req[req[indx]][0] # cliente
n_blk =
d_req[req[indx]][2] # blocchi da
leggere
t_serv =
abs(trk-trk_serv)*t_trk + n_blk * t_blk
s_req.append(trk_serv)
del
req[indx] # elimino
richiesta servita
logga('Coda out:',repr(req))
sema_req.release() # rilascio aggiornamento richieste
sleep(t_serv) #
simulo tempo di spostamento + lettura
trk = trk_serv
exec(cliente + '.set()') # fine servizio
o_req = [] #
richieste originarie
for i in
range(0,len(s_req)):
o_req.append(d_req[i+1][1])
logga('trk chiesta',str(o_req[i]))
logga('trk
servita',str(s_req[i]))
t_teorico
= t_reale = 0 # assegnazione multipla
for i in
range(1,len(o_req)):
t_teorico
= t_teorico + abs(o_req[i] - o_req[i-1]) * t_trk
t_reale = t_reale + abs(s_req[i] - s_req[i-1]) * t_trk
logga('Tempo teorico:', str(t_teorico))
logga('Tempo reale: ',
str(t_reale))
logga('--- Fine Servente ---')
fl.close()
simula()