Decoratori

Video explanation

Le funzioni, essendo oggetti, possono essere passate come parametro di un’altra funzione.

def hello(name):
	return f"hello {name}"
	
def welcome(name):
	return f"welcome {name}"
	
def greetBob(function):
	return function("Bob")
	
print(greetBob(hello))			# hello Bob
print(greetBob(welcome))		# welcome Bob

Questo comportamento ci può venire utile per essere sicuri che alcune funzioni vengano chiamate con i giusti parametri, o per calcolare il tempo di esecuzione di una funzione.

from time import time
 
def CalculateTime(func):			# decoratore
	def timer(*args, **kargs):
		start_time = int(round(time() * 1000000))
		res = func(*args, *kargs)
		stop_time = int(round(time() * 1000000))
		print(f"Elapsed time {stop_time-start_time}\u03BCs")
		return res
	return timer
		
@CalculateTime						# decorazione
def calcola(x, y):
	return x+y
	
# è equivalente a: CalculateTime(calcola)

Classi come decoratori

Le classi possono essere anche utilizzate come decoratori.

class D:
	def __init__(self, type):
		self.type = type
	
	def __call__(self, inappname):
		def getInAppFinalID():
			return self.type + "." + inappname()
		return getInAppFinalID
 
@D("MAINGROUPID")
def inAppID():
	return "com.team.appname"

D prende come parametro init una stringa type, istanzia l’oggetto e passa la funzione inAppID come parametro alla funzione __call__ di D, che ritorna la funzione getInAppFinalID() e la assegna alla funzione inAppID. Quando si chiama la funzione inAppID, quindi, in realtà si sta chiamando la funzione getInAppFinalID, che utilizza inAppID come parametro.


Decorare una classe

Non solo i metodi, ma anche le classi possono essere decorate. La funzione prende quindi in input una classe, e restituisce un’altra classe (la classe decorata) in output.

def SCD(C):
	C.newmethod = lambda self, x: self.z+x
	return C
	
@SCD
class B:
	z = 3
 
l = B()
l.newmethod(23)