Python

Python è un linguaggio a tipizzazione dinamica.

In Python tutto è un oggetto, anche le classi.

Operazioni

Le operazioni disponibili sono le seguenti:

+, -, *               # Addizione, sottrazione e moltiplicazione
/                     # Divisione (risultato comunque convertito a float)
**                    # Elevamento a potenza
//, %                 # Quoziente e resto
a >> n, a << n        # Shift dx/sx di n posizioni di a
a & b, a | b          # And/or bitwise

Object oriented programming in python

Essendo tutto una classe in python, ci deve essere un punto di singolarità da cui tutto parte, e questo punto è type.

type

La classe type ha come tipo se stessa.

type(type)				# <class 'type'>
print(type.__class__)	# stesso risultato di sopra

Non ha senso parlare di attributi o variabili di classe o di istanza, perchè esistono solo oggetti e i loro attributi.

Se gli oggetti sono classi, le istanze non hanno particolari diritti sugli attributi.

Accesso agli attributi

L’accesso agli attributi è diverso da linguaggi come Java.

class foo:
	s = 0
	def get(self):
		return s
		
	def somma(self, y, x):
		s = x+y

Il problema di questo codice è che la funzione get() restituisce un errore, in quanto l’attributo s non viene trovato. Questo perchè nel namespace locale non c’è, e nemmeno in quello enclosing. Quindi, se ci fosse un’assegnazione (come in somma) sarebbe a livello locale. Dal momento che vuole recuperare il valore, viene lanciato un errore.

Infatti, se si chiama la funzione somma, l’assegnazione interna è a livello locale, quindi:

f = foo()
f.somma(2, 3)
f.s					# s = 0

Se si prova ad accedere ad un attributo, come nella funzione get, solo attraverso il suo identificativo, il compilatore lo cerca tramite il principio LEGB. Se invece si prova ad accedere ad un attributo tramite l’oggetto nel quale è contenuto, come ad esempio O.s, l’oggetto O viene risolto tramite LEGB, e poi si cerca l’attributo nell’oggetto tramite catena ereditaria in cui l’oggetto è inserito.

Ricerca attributi

Il tipo di ricerca dipende da come si cerca di accedere all’attributo. Se si cerca di accedere ad un attributo tramite O.a, allora si cerca prima O, e poi si cerca l’attributo.

Override di attributi

Se più superclassi di una classe A definiscono un attributo con lo stesso nome, A vedrà solo l’attributo della classe che compare prima nell’MRO. Si applica anche a funzioni con lo stesso nome, anche se hanno signature differente. Python non supporta l’overloading di metodi.

Variabili statiche

class foo:
	s = 0
	def get(self):
		return foo.s
		
	def somma(self, y, x):
		foo.s = x+y

Qui l’attributo classe s viene usato da tutte le istanze di foo, quindi è paragonabile ad un attributo statico.

Metodi bound e unbound

I metodi bound sono metodi chiamati da un’istanza della classe, e ai quali questa istanza viene legata, per non perdere il legame. L’istanza viene passata automaticamente dal compilatore come primo parametro.

I metodi unbound, invece, vengono chiamati a livello di classe, e nessuna istanza viene passata come parametro.

Ereditarietà

Una classe A è superclasse di B, se A è una classe base di B o se A è una classe base di una superclasse di B.

class A:
	pass
	
class B(A):
	pass
	
class C(B):
	pass

A è superclasse sia di B che di C, e B è superclasse di C.

Si può anche dire che A è antenato di B, e B è discendente di A.

Come già visto, Python supporta anche l’Ereditarietà multipla. Per gestire l’Ereditarietà multipla, che può essere vista come un grafo, si utilizza MRO.