USARE GLI OGGETTI FUNZIONE

Prima di affrontare l’argomento “I Namespace in Python” facciamo ancora qualche considerazione sulle funzioni. Se usiamo le parentesi tonde dopo la funzione significa che stiamo chiamando la funzione, se utilizziamo nel programma solamente il nome della funzione significa che ci stiamo riferendo alla funzione come ad un oggetto la cui istanza appartiene alla classe function.

Function Type

Questo significa che le funzioni sono oggetti e sono istanze della classe function. Vediamo quali sono le principali caratteristiche nell’usare le funzioni come oggetti.

FUNZIONI NIDIFICATE

Vediamo subito un esempio di come possono essere nidificate le funzioni all’interno dei nostri programmi.

Funzioni nidificate

FUNZIONE COME VALORE DI RITORNO

Una funzione può essere ritornata come valore. La funzione nidificata ritorna un oggetto, la funzione inner(a,b). Abbiamo detto che se ci riferiamo alla funzione solo con il suo nome di fatto stiamo accedendo alla funzione come oggetto, non la stiamo invocando. Possiamo ritornare una funzione nidificata all’esterno dalla funzione che l’ha creata outer() e invocarla. f punta ad una funzione, passando ad essa i suoi argomenti possiamo invocare la funzione ritornata come oggetto.

Funzione come valore di ritorno

FUNZIONE COME PARAMETRO

Possiamo passare un oggetto funzione come parametro di un oggetto di un’altra funzione.

Funzione come parametro

NAMESPACE E SCOPE

I namespace in Python sono una mappatura di nomi ad oggetti. Vengono usati per mantenere distinti i nomi che assegniamo agli oggetti in zone diverse del programma così da evitare collisioni di nomi. In pratica servono a garantire l’univocità dei nomi usati nei programmi. A runtime cioè quando un programma va in esecuzione ci sono multipli namespace, essi sono organizzati in forma gerarchica, inoltre hanno cicli di vita differenti.

Namespace

LO SCOPE

Quando si parla di scope, cioè di contesto, si intende un’area di codice dove ci si trova in un certo momento che determina quale namespace deve essere utilizzato da Python per la risoluzione dei nomi di oggetti.

Scope

GERARCHIA DEI NAMESPACE

Abbiamo detto che i namespace sono organizzati gerarchicamente, partendo per la risoluzione dei nomi da quelli inferiori per poi risalire verso quelli superiori.

Gerarchia

LOCAL SCOPE

Il Local scope è il livello interno di una funzione, gli argomenti e le variabili che si trovano all’interno di essa  formano il Local Namespace. Viene creato quando invochiamo una funzione e viene rimosso quando la funzione ritorna. x, y e c sono argomenti e variabili che formano il Local Namespace della funzione sum.

Local scope

ENCLOSED SCOPE

Se ci alziamo di un livello troviamo L’Enclosed Scope. La funzione inner() nidificata nella funzione outer(x) sta utilizzando due variabile x e y. Python ver verificare queste due variabili risale di un livello e le trova definite una come parametro e l’altra definita all’interno della funzione outer(x). Python risalendo la gerarchia è in grado di risolvere le variabili x e y definite nella funzione nidificata. Supponendo che non sia riuscito a risolvere le variabili, sale ancora di un livello in quello che si chiama Global Scope.

Enclosed Scope

GLOBAL NAMESPACE

x che vale 100 è una variabile globale perché definita al di fuori di tutte le funzioni. Nel momento in cui viene richiamata myFunc(y) l’argomento y viene risolto nel Namespace Local. Per la variabile x Python sale a livello di sorgente e la risolve. L’ultimo Namespace che è gerarchicamente quello più in alto di tutti si trovano le definizioni delle funzioni predefinite. Viene fornito direttamente dall’ambiente di runtime di Python. Contiene le funzioni predefinite come detto o Built-in ad esempio print che abbiamo utilizzato molte volte.

Global scope

BUILT-IN NAMESPACE

Namespace predefinito che contiene le funzioni predefinite in Python.

Built-in Namespace

GLOBAL E NONLOCAL

Le parole chiave global e nonlocal servono ad alterare il meccanismo dei namespace già visto. Prima di introdurle vediamo il concetto dell’information Hiding.

INFORMATION HIDING

Se una funzione definisce una variabile locale già presente ad un livello più alto della gerarchia questa nasconde la variabile globale. Quando si esce al di fuori di myFunc() print(x) stamperà la variabile che si trova nel namespace globale. Quello che abbiamo visto è il comportamento standard di Python. Tale comportamento si può alterare utilizzando le parole chiave global e nonlocal.

Variable Hiding

LO STATEMENT GLOBAL

Lo statement global fa in modo che la variabile locale x diventi globale. Quindi print(x) stamperà 20 non 100. MyFunc() non crea una nuova variabile globale ma usa quella esistente. Quando stampiamo il valore 100 diventerà 20.

Global

LO STATEMENT NONLOCAL

Lo statement nonlocal agisce in modo simile a global però in questo caso si accede al namespace di una funzione esterna outer(). con nonlocal dichiariamo che vogliamo utilizzare una variabile y interna alla inner() non locale a tale funzione ma che si trova ad un livello più alto della gerarchia, cioè in outer().

non local

FUNCTION DECORATOR

Un Decorator è una funzione che prende in input come parametro una funzione la arricchisce di istruzioni aggiungendo del proprio codice e poi ritorna come valore di ritorno non la funzione passata in input ma il decorator. Tutto ciò serve a arricchire il comportamento di una funzione già esistente con del codice senza modificare la funzione originale.

def myDecorator(f):
    def decorator():
        print('Ho decorato')
        f()
    return decorator

@myDecorator
def myFunc():
    print('La Funzione myFunc')
myFunc()

FUNZIONI LAMBDA

Oltre all’istruzione def Python consente di creare una funzione con una espressione lambda che genera un oggetto funzione. Invece di assegnare un nome alla funzione con l’istruzione def la funzione lambda fa ritornare una funzione anonima.

Lambda
lambda
import math
#ELEVAMENTO A POTENZA
f=lambda x,y:math.pow(x,y)
print(f(2,3))
#SENO DI UN NUMERO
f=lambda v:math.sin(v)
print(f(180))
#STAMPA LA RADICE QUADRATA DI UN NUMERO PASSATO COME ARGOMENTO
f=lambda x:math.sqrt(x)
print(f(144))
#CONCATENA DUE VALORI
f=lambda s1,s2:s1+s2
print(f('Hello ','World!'))
#FUNZIONI RICORSIVE CALCOLO DEL FATTORIALE
#DI UN NUMERO
def fattoriale(n):
    """Il fattoriale di un numero
    indica il prodotto di
    quel numero per tutti i suoi antecedenti"""
    if n == 1:
        return 1
    else:
        return (n * fattoriale(n-1))
res = int(input("Inserisci un numero: "))
if res >= 1:
   print("Il fattoriale di", res, "è", fattoriale(res))

APPROFONDIMENTO

In Python, una funzione è un blocco di codice che può essere riutilizzato per eseguire un’attività specifica. Gli “oggetti funzione” si riferiscono al fatto che le funzioni in Python sono oggetti a tutti gli effetti e possono essere manipolati come tali. Ecco alcune caratteristiche chiave degli oggetti funzione in Python:

1. Definizione delle Funzioni:

Le funzioni vengono definite utilizzando la parola chiave def seguita dal nome della funzione e dalle parentesi che possono contenere parametri.

def saluta(nome):
     return f”Ciao, {nome}!”

2. Le Funzioni sono Oggetti di Prima Classe:

In Python, le funzioni sono trattate come oggetti di prima classe, il che significa che possono essere assegnate a variabili, passate come argomenti ad altre funzioni, e ritornate da altre funzioni.

def saluta(nome):
       return f”Ciao, {nome}!”

messaggio = saluta # Assegno la funzione a una variabile
print(messaggio(“Luca”)) # Chiamo la funzione tramite la variabile

3. Funzioni come Argomenti:

Le funzioni possono essere passate come argomenti ad altre funzioni.

def applica_funzione(f, valore):
       return f(valore)

def raddoppia(x):
       return x * 2

risultato = applica_funzione(raddoppia, 5) # Passo la funzione raddoppia come argomento
print(risultato) # Stampa: 10

4. Funzioni che Ritornano Funzioni:

Le funzioni possono ritornare altre funzioni, consentendo di creare fabbriche di funzioni.

def crea_moltiplicatore(m):
      return lambda x: x * m

raddoppia = crea_moltiplicatore(2)
triplica = crea_moltiplicatore(3)

print(raddoppia(5)) # Stampa: 10
print(triplica(5)) # Stampa: 15

Queste sono le basi degli oggetti funzione in Python. Le funzioni sono estremamente flessibili e potenti, e comprendere come funzionano come oggetti può aiutare a scrivere codice più modulare e riutilizzabile.

I NAMESPACE IN PYTHON IL LINK AL CODICE GITHUB

GITHUB

I NAMESPACE IN PYTHON LINK AI POST PRECEDENTI

PREVIOUS POST LINKS