User Input and Error Handling¶
da PowerShell -- jupyter nbconvert --to html notebook.ipynb¶
In [3]:
# ho un file altutde.py che cintiene una istruzione "input"
import altitude
57.216187274208295
In [11]:
# ho un file altitude_cml.py e lo uso da PowerShell : python altitude_cml.py 6490
Flexible User Input with eval end exec¶
In genere, il modo più sicuro per gestire i dati di input sotto forma di stringhe di testo è convertirli nel tipo di variabile specifico necessario nel programma. Lo abbiamo fatto sopra, utilizzando le conversioni di tipo int(...) e float(...), e vedremo più avanti come tali conversioni possano essere rese a prova di errore e gestire input utente non pertinenti.¶
Tuttavia, Python offre anche un paio di funzioni più flessibili per gestire i dati di input, ovvero $eval$ ed $exec$, che è utile conoscere.¶
"eval"¶
In [21]:
s = '1+2'; r = eval(s); print(r)
print(type(r))
r = eval('[1, 6, 7.5] + [1, 2]'); print(r)
print(type(r))
3 <class 'int'> [1, 6, 7.5, 1, 2] <class 'list'>
In [25]:
i1 = eval(input('operand 1: '))
i2 = eval(input('operand 2: '))
r = i1 + i2
print(f'{type(i1)} + {type(i2)} becomes {type(r)} with value{r}')
<class 'float'> + <class 'float'> becomes <class 'float'> with value7.300000000000001
In [27]:
import add_input
# se in input ho una list, mi dà errore
<class 'int'> + <class 'int'> becomes <class 'int'> with value7
"exec"¶
Una input del tipo "r = 1+1", eval non lo gestisce, exec invece sì¶
In [34]:
expression = '1+1' #store expression in a string
statement = 'r = 1+1' # store statement in a string
q = eval(expression)
exec(statement)
print(q,r) # results are the same
2 2
In [52]:
from math import *
somecode = """
def f(x):
a = 9.81
w1 = 0.1
w2 = 0.3
term1 = exp(-a*x) * sin(w1*x)
term2 = 2 * sin(w2*x)
return term1 + term2
"""
exec(somecode)
x = 0
while x is not None:
s = input('Give x (None to quit): ').strip()
if s == "":
break # invio vuoto → termina il programma
x = eval(s) # qui eval riceve SEMPRE qualcosa di valido
if x is not None:
y = f(x)
print(f'f({x}) = {y}')
f(3.1) = 1.603239881767573
In [62]:
from math import *
formula = "x**3 + 2*x**2" # simulazione input da CLI
x0 = 2.0
code = f"""
def f(x):
return {formula}
"""
exec(code)
def numerical_derivative(f, x, h=1E-5):
return (f(x + h) - f(x - h)) / (2*h)
print(f'Numerical derivative: {numerical_derivative(f, x0)}')
Numerical derivative: 20.00000000030866
In [ ]:
# da riga di comando ho il file deriv.py --- python deriv.py "x**3 + 2*x**2" 2
Reading Data from Files¶
In [7]:
"""
21.8
18.1
19
23
26
17.8
"""
mean = 0.0
lines = 0
infile = open('data.txt', 'r') # open file
for line in infile:
number = float(line) # line is string
mean = mean + number
lines += 1
mean = mean/lines
print(f'The mean value is {mean}')
The mean value is 20.95
In [5]:
mean = 0.0
lines = 0
with open('data.txt', 'r') as infile: # open file
for line in infile:
number = float(line) # line is string
mean = mean + number
lines += 1
mean = mean/lines
print(f'The mean value is {mean}')
The mean value is 20.95
In [25]:
mean = 0
lines = 0
icount = 0
infile = open('data.txt', 'r') # open file
lines = infile.readlines()
infile.close()
for line in lines:
number = float(line) # line is string
mean = mean + number
icount += 1
print(f'The mean value is {mean/icount}')
The mean value is 20.95
Si può leggere il file in un'unica stringa - poi uso split¶
In [30]:
infile = open('data.txt', 'r') # open file
text = infile.read()
print(type(text))
<class 'str'>
In [32]:
s = "This is a typical string"
csvline = "Excel;sheets;often;use;semicolon;as;separator"
print(s.split())
print(csvline.split())
print(csvline.split(';'))
['This', 'is', 'a', 'typical', 'string'] ['Excel;sheets;often;use;semicolon;as;separator'] ['Excel', 'sheets', 'often', 'use', 'semicolon', 'as', 'separator']
Abbiamo un file di dati sulle precipitazioni¶
In [56]:
"""
Average rainfall (in mm) in Rome: 1188 months between 1782 and 1970
Jan 81.2
Feb 63.2
Mar 70.3
Apr 55.7
May 53.0
Jun 36.4
Jul 17.5
Aug 27.5
Sep 60.9
Oct 117.7
Nov 111.0
Dec 97.9
Year 792.9
"""
months = []
values = []
infile = open('rainfall.txt', 'r') # open file
infile.readline() # skip the first line
for line in infile:
words = line.split() # split into words
months.append(words[0])
values.append(float(words[1]))
In [60]:
def extract_data(filename):
infile = open(filename, 'r')
infile.readline() # skip the first line
months = []
rainfall = []
for line in infile:
words = line.split() #words[0]: month, words[1]: rainfall
months.append(words[0])
rainfall.append(float(words[1]))
infile.close()
months = months[:-1] # Drop the "Year" entry
annual_avg = rainfall[-1] # Store the annual average
rainfall = rainfall[:-1] # Redefine to contain monthly data
return months, rainfall, annual_avg
months, values, avg = extract_data('rainfall.txt')
#print('The average rainfall for the months:')
for month, value in zip(months, values):
#print(month, value)
a = 1
print('The average rainfall for the year:', avg)
The average rainfall for the year: 792.9
Writing Data to Files¶
Prendo i dati da una "nested list" e li scrivo in tmp_table.dat¶
In [68]:
data = \
[[ 0.75, 0.29619813, -0.29619813, -0.75 ],
[ 0.29619813, 0.11697778, -0.11697778, -0.29619813],
[-0.29619813, -0.11697778, 0.11697778, 0.29619813],
[-0.75, -0.29619813, 0.29619813, 0.75 ]]
with open('tmp_table.dat', 'w') as outfile:
for row in data:
for column in row:
outfile.write(f'{column:14.8f}')
outfile.write('\n')
Handling Errors in Programs¶
In [ ]:
try:
<statements we intend to do>
except:
<statements for handling errors>
In [ ]:
# esecuzione sole da riga di comando - altitude_cml_except1.py
import sys
from math import exp
try:
h = float(sys.argv[1])
except IndexError:
print('No command line argument for h!')
sys.exit(1) # abort execution
except ValueError:
print(f'h must be a pure number, not {sys.argv[1]}')
exit()
except:
print('Something went wrong in reading input data!')
exit()
p0 = 100.0; h0 = 8400
print(p0 * exp(-h/h0))
Possiamo scrivere Eccezioni personalizzate¶
In [ ]:
import sys
from math import exp
def read_altitude():
try:
h = float(sys.argv[1])
except IndexError:
# re-raise, but with specific explanation:
raise IndexError(
'The altitude must be supplied on the command line.')
except ValueError:
# re-raise, but with specific explanation:
raise ValueError(
f'Altitude must be number, not "{sys.argv[1]}".')
# h is read correctly as a number, but has a wrong value:
if h < -430 or h > 13000:
raise ValueError(f'The formula is not valid for h={h}')
return h
# la formula è valida solo nella troposfera, da 430 m a 13 km
Possiamo fermare l'esecuzione e farce descrivere il tip di errore¶
In [ ]:
try:
h = read_altitude()
except (IndexError, ValueError) as e:
# print exception message and stop the program
print(e)
exit()
Making Modules¶
$math$ e $sys$ sono Modules¶
Possono contenere dati, funzioni, classi - Ne possiamo scrivere dei nostri personali - es. molte formule per l'interesse¶
$P=\, initial\, amount$ -- $r=\, interest\, rate$ -- $n=\, numero\, anni$ -- $A=\,final\, amount$¶
In [ ]:
from math import log as ln
"""
def present_amount(P, r, n):
return P*(1 + r/100)**n
def initial_amount(A, r, n):
return A*(1 + r/100)**(-n)
def years(P, A, r):
return ln(A/P)/ln(1 + r/100)
def annual_rate(P, A, n):
return 100*((A/P)**(1.0/n) - 1)
"""
# le scrivo in interest.py
In [84]:
from interest import years
P = 1; r = 5
n = years(P, 2*P, r)
print(f'Money has doubled after {n} years')
Money has doubled after 14.206699082890463 years
name. Questa variabile stringa viene creata automaticamente ed è sempre definita durante l'esecuzione di Python¶
In [90]:
from interest import *
P = 1; r = 5
n = years(P, 2*P, r)
if __name__ == '__main__':
A = 2.31525
P = 2.0
r = 5
n = 3
A_ = present_amount(P, r, n)
P_ = initial_amount(A, r, n)
n_ = years(P, A, r)
r_ = annual_rate(P, A, n)
print(f'A={A_} ({A}) P={P_} ({A}) n={n_} ({n}) r={r_} ({r})')
A=2.3152500000000003 (2.31525) P=1.9999999999999998 (2.31525) n=2.999999999999996 (3) r=5.000000000000004 (5)
Voglio testare tutte le funzioni¶
In [119]:
def test_all_functions():
# Define compatible values
A = 2.31525; P = 2.0; r = 5.0; n = 3
# Given three of these, compute the remaining one
# and compare with the correct value (in parenthesis)
A_computed = present_amount(P, r, n)
P_computed = initial_amount(A, r, n)
n_computed = years(P, A, r)
r_computed = annual_rate(P, A, n)
def float_eq(a, b, tolerance=1E-12):
"""Return True if a == b within the tolerance."""
return abs(a - b) < tolerance
success = float_eq(A_computed, A) and float_eq(P_computed, P) and float_eq(r_computed, r) and float_eq(n_computed, n)
assert success # could add message here if desired
print(success) # <-- stampa True se tutto ok
if __name__ == '__main__':
test_all_functions()
True
Dove Python cerca i moduli¶
Nella cartella di lavoro, ma può essere poco funzionale - in una dir designata, chaggiungo con riga di comando¶
In [ ]:
export PYTHONPATH=/Users/sundnes/lib/python/mymods
Possiamo mettere il Path in .bashrc che sta nella Home dir )e.g. /Users/Gian/.bashrc¶
E nascosta, la trovo e la apro da EveryThing¶
Oppure la mettiamo in "site-packages" --- per trovarla¶
In [130]:
import numpy
numpy.__file__
Out[130]:
'C:\\Users\\Gian\\venv\\Lib\\site-packages\\numpy\\__init__.py'
In [ ]: