Metodi Informatici per la Biologia Esercitazione 8 1. Altri dettagli sulle funzioni Come ormai sapete bene, la forma generale di una funzione è: def nome_funzione(argomento1, argomento2,…): "documentazione" istruzione1 istruzione2 … istruzione n return variabile1, variabile2, … Rivediamo alcuni concetti chiave: Nomi globali e locali: le variabili utilizzate all’interno del corpo di una funzione sono proprie solo della funzione, e non accessibili al di fuori della funzione. Quando una funzione ritorna una variabile, ne ritorna solo il valore, e non la variabile stessa. Al contrario, le variabili create al di fuori di una funzione sono globali e generalmente accessibili all’interno della funzione. Quando si passa una variabile a una funzione, in realtà non si passa la variabile ma solo il suo valore. Nella definizione della funzione, i nomi degli argomenti definiscono nuove variabili locali che conterranno i valori passati durante la chiamata della funzione. Quando una funzione non ha un’istruzione di return, python lo segnala ritornando comunque un tipo di dato nullo (None). >>> def quadrato(n): ... q = n ** 2 ... >>> n = 4 >>> print quadrato(n) None >>> print q Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'q' is not defined >>> def stampa(stringa): ... print stringa ... >>> s = "ciao" >>> stampa(s) ciao >>> print stampa(s) ciao None >>> a = stampa(s) ciao >>> print a None >>> type(a) <type 'NoneType'> Non tutto ciò che è esterno a una funzione è inaccessibile al suo interno: ad esempio, se importiamo una libreria al di fuori della funzione, i metodi della libreria sono accessibili anche all’interno della funzione. Oppure, se creiamo una qualsiasi funzione, questa funzione è chiamabile da altre funzioni. >>> def quadrato(n): ... q = math.pow(n,2) ... return q ... >>> import math >>> print quadrato(n) 16.0 >>> def somma_di_quadrati(n1,n2): ... q1 = quadrato(n1) ... q2 = quadrato(n2) ... s = q1 + q2 ... return s ... >>> print somma_di_quadrati(4,5) 41.0 Nomi degli argomenti: una conseguenza è che i nomi degli argomenti che la funzione richiede in input sono nomi locali. Quando la funzione viene chiamata, passandogli delle variabili, i nomi di queste variabili non devono necessariamente essere uguali a quelli degli argomenti. >>> ... ... ... ... ... >>> >>> >>> >>> 10 >>> 100 >>> -10 def somma(L): somma = 0 for n in L: somma = somma + n return somma L1 = [1,2,3,4] L2 = [10,20,30,40] L3 = [-1,-2,-3,-4] print somma(L1) print somma(L2) print somma(L3) Posso anche passare a una funzione dei valori invece che variabili, e questi valori saranno assegnati ai nomi delle variabili che la funzione richiede come argomenti e che userà al suo interno >>> ... ... ... >>> 30 >>> >>> 15 def somma_due_numeri(a,b): somma = a + b return somma print somma_due_numeri(10,20) num = 5 print somma_due_numeri(num,10) 2. Altri dettagli sui dizionari I dizionari sono tipi di dati organizzati come coppie chiave:valore. Le chiavi di un dizionario sono uniche, cioè nel dizionario ci può essere una sola istanza di una data chiave. Se cerco di assegnare una nuova coppia chiave:valore al dizionario, ma la chiave è già presente, semplicemente viene sostituito il precedente valore associato a quella chiave con il nuovo valore >>> D = {"MYC":5.4, "JUN":0.3} >>> D["FOS"] = 2.2 >>> D["MYC"] = 7.0 >>> print D {'MYC': 7.0, 'JUN': 0.3, 'FOS': 2.2} Valori associati a chiavi diverse possono essere invece identici. Una conseguenza è che data una chiave, posso accedere direttamente al valore ad esso associato, se la chiave è presente nel dizionario (altrimenti ottengo un errore), mentre dato un valore non posso accedere direttamente alla chiave, o alle chiavi, ad esso associate >>> print D["MYC"] 7.0 >>> print D["MAX"] Traceback (most recent File "<stdin>", line KeyError: 'MAX' >>> print D[7.0] Traceback (most recent File "<stdin>", line KeyError: 7.0 call last): 1, in <module> call last): 1, in <module> Come faccio allora a pescare le chiavi associate ad un dato valore? Devo iterare per tutte le chiavi nel dizionario, esaminare il valore associato a ciascuna e confrontarlo col valore che mi interessa. >>> for chiave in D.keys(): ... valore = D[chiave] ... if valore == 7.0: ... print chiave ... MYC Esercizi: 1. La circonferenza di un cerchio è calcolata come (2 * pi greco * raggio). Scrivete una funzione che calcola e ritorna la circonferenza dato il raggio. 2. L’area di un cerchio può essere calcolata come circonferenza * raggio / 2. Scrivete una funzione che calcola e ritorna l’area di un cerchio dato il raggio, la quale chiama la funzione che calcola la circonferenza che avete scritto prima. 3. In condizioni ottimali, un singolo E.coli si divide in 20 minuti. Scrivete una funzione che calcoli il numero di cellule di E. coli che si generano partendo da una singola cellula, dato come argomento il numero di ore passate 4. Scrivete una funzione che prende una stringa e per ogni lettera della stringa scrive se è una vocale o una consonante 5. Data una lista di stringhe (ad es. di nomi), scrivete una funzione che prenda questa lista come argomento e restituisca un dizionario che abbia come chiavi le stringhe e come valori la loro lunghezza Soluzioni 1. La circonferenza di un cerchio è calcolata come (2 * pi greco * raggio). Scrivete una funzione che calcola e ritorna la circonferenza dato il raggio >>> def circonferenza(raggio): ... from math import pi ... circ = 2 * pi * raggio ... return circ ... >>> r = 10 >>> print circonferenza(r) 62.8318530718 2. L’area di un cerchio può essere calcolata come circonferenza * raggio / 2. Scrivete una funzione che calcola e ritorna l’area di un cerchio dato il raggio, la quale chiama la funzione che calcola la circonferenza che avete scritto prima. >>> def area_cerchio(raggio): ... circ = circonferenza(raggio) ... area = circ * raggio / 2 ... return area ... >>> r = 10 >>> print area_cerchio(r) 314.159265359 3. In condizioni ottimali, un singolo E.coli si divide in 20 minuti. Scrivete una funzione che calcoli il numero di cellule di E. coli che si generano partendo da una singola cellula, dato come argomento il numero di ore passate >>> def crescita(ore): ... minuti = 60 * ore ... tempo_divisione = 20 ... numero_divisioni = minuti / float(tempo_divisione) ... numero_cellule = math.pow(2,numero_divisioni) ... return numero_cellule ... >>> import math >>> print crescita(6) 262144.0 4. Scrivete una funzione che prende una stringa e per ogni lettera della stringa scrive se è una vocale o una consonante >>> def trova_vocali(S): ... vocali = ["A","E","I","O","U"] ... for s in S: ... if s.upper() in vocali: ... print s,"vocale" ... else: ... print s,"consonante" ... >>> trova_vocali("Ciccio") C consonante i vocale c consonante c consonante i vocale o vocale 5. Data una lista di stringhe (ad es. di nomi), create un dizionario che abbia come chiavi le stringhe e come valori la loro lunghezza >>> def trova_lunghezza(L): ... D = {} ... for nome in L: ... D[nome] = len(nome) ... return D ... >>> Lista = ["Fabrizio","Ciccio","Iolanda","Manuela"] >>> print trova_lunghezza(Lista) {'Manuela': 7, 'Fabrizio': 8, 'Ciccio': 6, 'Iolanda': 7} Esercizi 6. Data la sequenza di una proteina, scrivete una funzione che ne calcoli e ritorni la carica netta usando carica +1 per ogni R o K e -­‐1 per ogni D o E 7. Ora scrivete una funzione che prenda come argomento una sequenza di una proteina, e per ogni segmento lungo 10 aminoacidi contenuto in essa (ad es. dal primo al decimo aminoacido, dall’undicesimo al ventesimo, e cosi via) ne calcoli la carica chiamando la funzione scritta prima, e restituisca una lista contenente la carica di ogni segmento 8. Scrivete una funzione che data una sequenza di DNA ritorna un dizionario contenente le frequenze dei 4 nucleotidi 9. Scrivete una funzione che calcoli la radice ennesima di un numero, dati in input il numero e la base della radice (ad es. 3 per la radice cubica, 4 per la radice quarta, e cosi via). Ricordate che la radice in base n di un numero è uguale al numero elevato 1/n, quindi la radice quadrata di un numero può essere scritta come numero ** (1 / 2.0) 10. Scrivete una funzione che calcoli la media geometrica di una lista di numeri. La media geometrica di n numeri è la radice n-­‐esima del loro prodotto. Usate per calcolare la radice n-­‐esima la funzione che avete definito al punto 9 Soluzioni 6. Data la sequenza di una proteina, scrivete una funzione che ne calcoli e ritorni la carica netta usando carica +1 per ogni R o K e -­‐1 per ogni D o E >>> def calcola_carica(seq): ... positivi = ["R","K"] ... negativi = ["D","E"] ... carica = 0 ... for amino in seq: ... if amino in positivi: ... carica = carica + 1 ... else: ... if amino in negativi: ... carica = carica - 1 ... return carica ... >>> seq = "ARKRRTAFDEGHHYILMMREEDFERRAAQWERRRRRR" >>> print calcola_carica(seq) 6 7. Ora scrivete una funzione che prenda come argomento una sequenza di una proteina, e per ogni segmento lungo 10 aminoacidi contenuto in essa (ad es. dal primo al decimo aminoacido, dall’undicesimo al ventesimo, e cosi via) ne calcoli la carica chiamando la funzione scritta prima, e restituisca una lista contenente la carica di ogni segmento >>> ... ... ... ... ... ... ... >>> >>> [2, def carica_segmenti(seq): L = [] for i in range(0,len(seq),10): segmento = seq[i:i+10] carica = calcola_carica(segmento) L.append(carica) return L seq = "ARKRRTAFDEGHHYILMMREEDFERRAAQWERRRRRR" print carica_segmenti(seq) 0, -1, 5] 8. Scrivete una funzione che data una sequenza di DNA ritorna un dizionario contenente le frequenze dei 4 nucleotidi >>> def frequenze(DNA): ... nucleotidi = ["A","C","T","G"] ... D = {} ... for nuc in nucleotidi: ... tot = DNA.count(nuc) ... freq = float(tot)/len(DNA) ... D[nuc] = freq ... return D ... >>> FREQ = frequenze("GCATCGATCATCGCTATCGACATCGATGCTGTATCT") >>> for nuc in FREQ.keys(): ... print nuc,round(FREQ[nuc],2) ... A 0.22 C 0.28 T 0.31 G 0.19 9. Scrivete una funzione che calcoli la radice ennesima di un numero, dati in input il numero e la base della radice (ad es. 3 per la radice cubica, 4 per la radice quarta, e cosi via). Ricordate che la radice in base n di un numero è uguale al numero elevato 1/n, quindi la radice quadrata di un numero può essere scritta come numero ** (1 / 2.0) >>> ... ... ... >>> 2.0 >>> 3.0 >>> 2.0 def radice_n(numero,n): radice = numero ** (1/float(n)) return radice radice_n(8,3) radice_n(27,3) radice_n(16,4) 10. Scrivete una funzione che calcoli la media geometrica di una lista di numeri. La media geometrica di n numeri è la radice n-­‐esima del loro prodotto. Usate per calcolare la radice n-­‐esima la funzione che avete definito al punto 4 >>> def media_geometrica(L): ... prodotto = 1 ... for numero in L: ... prodotto = prodotto * numero ... media = radice_n(prodotto,len(L)) ... return media ... >>> L = [1,2,3,4,5] >>> print media_geometrica(L) 2.6051710846973521