Generalità su "Class"¶
In [9]:
from math import exp
class Barometric:
def __init__(self, T): # metodo detto "costruttore" della classe
self.T = T #K # tutti questi self.* sono "attributi"
self.g = 9.81 #m/(s*s)
self.R = 8.314 #J/(K*mol)
self.M = 0.02896 #kg/mol
self.p0 = 100.0 #kPa
def value(self, h): # metodo "value"
return self.p0 * exp(-self.M*self.g*h/(self.R*self.T))
b1 = Barometric(T=245) # una istanza di Barometric (oggetto)
p1 = b1.value(2469) # metodo per calcolare la formula
print(p1)
70.86738432067067
In [21]:
from math import sin, exp, pi
from numpy import linspace
n = 3
def make_table(f,tstop,n):
for t in linspace(0,tstop,n):
print(t,f(t))
def g(t):
return sin(t)*exp(-t)
class Barometric:
def __init__(self, T): # metodo detto "costruttore" della classe
self.T = T #K # tutti questi self.* sono "attributi"
self.g = 9.81 #m/(s*s)
self.R = 8.314 #J/(K*mol)
self.M = 0.02896 #kg/mol
self.p0 = 100.0 #kPa
def value(self, h): # metodo "value"
return self.p0 * exp(-self.M*self.g*h/(self.R*self.T))
b1 = Barometric(T=245) # una istanza di Barometric (oggetto)
p1 = b1.value(2469) # metodo per calcolare la formula
make_table(g,2*pi,n) # invio di una funzione ordinaria
make_table(b1.value,2*pi,n) # invio di un metodo di classe
0.0 0.0 3.141592653589793 5.292178668034404e-18 6.283185307179586 -4.573915527954357e-19 0.0 100.0 3.141592653589793 99.95619273000563 6.283185307179586 99.91240465078029
Classi di Python più generali¶
Gli attributi possono essere definiti ovunque, anche fuori della Classe¶
In [ ]:
m = MyCalss(p1,p2,...)
m.new_attr = p3
Protected Class Attributes¶
Per un esempio informatico più classico di una classe Python, consideriamo una classe che rappresenta un conto bancario. Gli attributi naturali di una classe di questo tipo saranno il nome del titolare, il numero di conto e il saldo, e possiamo includere metodi per depositi, prelievi e stampa di informazioni sul conto.¶
In [40]:
class BankAccount:
def __init__(self, first_name, last_name, number, balance):
self._first_name = first_name # _first_name è una convenzione x dire dati riservati
self._last_name = last_name # da non essere usati al di fuori della Classe
self._number = number
self._balance = balance # saldo
def deposit(self, amount): # versamento
self._balance += amount
def withdraw(self, amount): # prelievo
self._balance -= amount
def print_info(self):
first = self._first_name;
last = self._last_name
number = self._number;
bal = self._balance
s = f'{first} {last}, {number}, balance: {bal}'
print(s)
a1 = BankAccount('John', 'Olsson', '19371564761', 20000)
a2 = BankAccount('Liz', 'Olsson', '19371564761', 20000)
a1.deposit(1000)
a1.withdraw(4000)
a2.withdraw(10500)
a1.withdraw(3500)
print("a1’s balance:", a1._balance)
a1.print_info()
a2.print_info()
a1’s balance: 13500 John Olsson, 19371564761, balance: 13500 Liz Olsson, 19371564761, balance: 9500
Special Methods¶
In [1]:
from math import exp
class Barometric:
def __init__(self, T): # metodo detto "costruttore" della classe, è un metodo speciale
self.T = T #K # tutti questi self.* sono "attributi"
self.g = 9.81 #m/(s*s)
self.R = 8.314 #J/(K*mol)
self.M = 0.02896 #kg/mol
self.p0 = 100.0 #kPa
def __call__(self, h): # è un metodo speciale
return self.p0 * exp(-self.M*self.g*h/(self.R*self.T))
baro = Barometric(245) # una istanza di Barometric
p = baro(2469) # posso calcolare col formalismo di una funzione
print(p)
70.86738432067067
Special Methods for Printing¶
Facciamo costruire dalla Classe un stringa da stampare -- metodo speciale "str"¶
In [15]:
from math import exp
class Barometric:
def __init__(self, T): # metodo detto "costruttore" della classe, è un metodo speciale
self.T = T #K # tutti questi self.* sono "attributi"
self.g = 9.81 #m/(s*s)
self.R = 8.314 #J/(K*mol)
self.M = 0.02896 #kg/mol
self.p0 = 100.0 #kPa
def __call__(self, h): # è un metodo speciale
return self.p0 * exp(-self.M*self.g*h/(self.R*self.T))
def __str__(self): # è un metodo speciale per costruire stringa comprensibile
return f'p0 * exp(-M*g*h/(R*T)); T = {self.T}'
b = Barometric(245) # una istanza di Barometric
b(2469) # posso calcolare col formalismo di una funzione e stampare
print(b)
p0 * exp(-M*g*h/(R*T)); T = 245
Special Methods for Mathematical Operations¶
In [ ]:
c = a+b #c = a.__add__(b) -- a, b istanze della Classe
c = a-b #c = a.__sub__(b)
c = a*b #c = a.__mul__(b)
c = a/b #c = a.__div__(b)
c = a**e #c = a.__pow__(e)
# These methods can return an object of the same type as the operands.
# Similarly, there are special methods for comparing objects,as follows:
a == b #a.__eq__(b)
a != b #a.__ne__(b)
a < b #a.__lt__(b)
a <= b #a.__le__(b)
a > b #a.__gt__(b)
a >= b #a.__ge__(b)
In [160]:
from math import exp
class Barometric:
def __init__(self, T): # metodo detto "costruttore" della classe, è un metodo speciale
self.T = T #K # tutti questi self.* sono "attributi"
self.g = 9.81 #m/(s*s)
self.R = 8.314 #J/(K*mol)
self.M = 0.02896 #kg/mol
self.p0 = 100.0 #kPa
def __call__(self, h): # è un metodo speciale
return self.p0 * exp(-self.M*self.g*h/(self.R*self.T))
def __str__(self):
return f'p0 * exp(-M*g*h/(R*T)); T = {self.T}'
def __repr__(self):
# Return code for regenerating this instance.
return f'Barometric({self.T})'
b = Barometric(271)
print(b)
print(repr(b))
b2 = eval(repr(b)) # repr(b) è un oggetto = repr(b2)
print(b2)
repr(b) == repr(b2)
p0 * exp(-M*g*h/(R*T)); T = 271 Barometric(271) p0 * exp(-M*g*h/(R*T)); T = 271
Out[160]:
True
In [46]:
class A:
def __init__(self, value):
self.v = value
a = A(2)
#dir(a)
print(a.__doc__)
print(b.__dict__) # contiene tutti gli attributi - è un Dizionario
print(a.v)
print(a.__module__)
None
{'T': 271, 'g': 9.81, 'R': 8.314, 'M': 0.02896, 'p0': 100.0}
2
__main__
Automatic Differentiation of Functions¶
In [61]:
class Derivative:
def __init__(self, f, h=1E-5):
self.f = f
self.h = float(h)
def __call__(self, x):
f, h = self.f, self.h #make short forms
return (f(x+h) - f(x))/h
def f(x):
return x**3
dfdx = Derivative(f)
print(dfdx(2))
from math import *
df = Derivative(sin)
x = pi
print(df(x))
12.000060000261213 -0.9999999999898844
Test Functions for Classes¶
In [114]:
def test_Derivative():
#The formula is exact for linear functions, regardless of h
f = lambda x: a*x + b
a = 3.5; b = 8
dfdx = Derivative(f, h=0.5) # la derivata non contiene x -- sempre verificata
diff = abs(dfdx(4.5) - a)
assert diff < 1E-14, 'bug in class Derivative, diff=%s'% diff
print(test_Derivative())
0.0 None
In [122]:
def test_Derivative_quadratic():
f = lambda x: x**2 + 3*x + 1
df_exact = lambda x: 2*x + 3
dfdx = Derivative(f, h=1e-6) # se h=1e-5 fallisce e python solleva una eccezione (tipo errore, ma non lo è)
x0 = 4.5
diff = abs(dfdx(x0) - df_exact(x0))
assert diff < 1e-6, f"Errore troppo grande: {diff}"
test_Derivative_quadratic()
Example - A Polynomial Class¶
In [166]:
class Polynomial:
def __init__(self, coefficients):
self.coeff = coefficients
def __call__(self, x):
return sum(a * x**i for i, a in enumerate(self.coeff))
def __add__(self, other): # somma di polinomi
if not isinstance(other, Polynomial):
return NotImplemented
n = max(len(self.coeff), len(other.coeff))
new_coeff = [0] * n
for i in range(n):
a = self.coeff[i] if i < len(self.coeff) else 0
b = other.coeff[i] if i < len(other.coeff) else 0
new_coeff[i] = a + b
return Polynomial(new_coeff)
def __mul__(self, other): # moltiplicazione di polinomi
if not isinstance(other, Polynomial):
return NotImplemented
n = len(self.coeff)
m = len(other.coeff)
new_coeff = [0] * (n + m - 1)
for i in range(n):
for j in range(m):
new_coeff[i + j] += self.coeff[i] * other.coeff[j]
return Polynomial(new_coeff)
def differentiate(self): # derivata del polinomio
if len(self.coeff) <= 1:
return Polynomial([0])
new_coeff = [
i * self.coeff[i]
for i in range(1, len(self.coeff))
]
return Polynomial(new_coeff)
def __str__(self): # scrittura come String visualizzabile
terms = []
for i, a in enumerate(self.coeff):
if a == 0:
continue
sign = "-" if a < 0 else "+"
a = abs(a)
if i == 0:
term = f"{a}"
elif i == 1:
term = "x" if a == 1 else f"{a}x"
else:
term = f"x^{i}" if a == 1 else f"{a}x^{i}"
terms.append((sign, term))
if not terms:
return "0"
first_sign, first_term = terms[0]
s = first_term if first_sign == "+" else f"-{first_term}"
for sign, term in terms[1:]:
s += f" {sign} {term}"
return s
p1 = Polynomial([1,-1])
print(p1)
p2 = Polynomial([0, 1, 0, 0, -6, -1])
print(p2)
p3 = p1 + p2
print(p3)
p4 = p1*p2
print(p4)
dp2 = p2.differentiate()
#print(dp2.coeff)
print(dp2)
1 - x x - 6x^4 - x^5 1 - 6x^4 - x^5 x - x^2 - 6x^4 + 5x^5 + x^6 1 - 24x^3 - 5x^4
In [ ]: