Articles

Quali sono gli spazi dei nomi Python (e perché sono necessari?)

I conflitti di nome si verificano tutto il tempo nella vita reale. Ad esempio, ogni scuola in cui sono andato aveva almeno due studenti nella mia classe che condividevano lo stesso nome. Se qualcuno entrasse in classe e chiedesse lo studente X, chiederemmo con entusiasmo: “Di quale stai parlando? Ci sono due studenti di nome X. ” Dopo di che, la persona indagatrice ci avrebbe dato un cognome, e gli avremmo presentato la destra X.

Tutta questa confusione e il processo di determinazione della persona esatta di cui stiamo parlando cercando altre informazioni oltre a un nome potrebbe essere evitato se tutti avessero un nome univoco. Questo non è un problema in una classe di 30 studenti. Tuttavia, diventerà sempre più difficile trovare un nome unico, significativo e facile da ricordare per ogni bambino in una scuola, città, città, paese o in tutto il mondo. Un altro problema nel fornire ogni bambino un nome univoco è che il processo di determinare se qualcun altro ha anche chiamato il loro bambino Macey, Maci o Macie potrebbe essere molto faticoso.

Un conflitto molto simile può anche sorgere nella programmazione. Quando si scrive un programma di sole 30 righe senza dipendenze esterne, è molto facile dare nomi univoci e significativi a tutte le variabili. Il problema sorge quando ci sono migliaia di linee in un programma e hai caricato anche alcuni moduli esterni. In questo tutorial, imparerai a conoscere gli spazi dei nomi, la loro importanza e la risoluzione dell’ambito in Python.

Cosa sono gli spazi dei nomi?

Uno spazio dei nomi è fondamentalmente un sistema per assicurarsi che tutti i nomi in un programma siano unici e possano essere utilizzati senza alcun conflitto. Potresti già sapere che tutto in stringhe, elenchi, funzioni simili a Python,ecc.- è un oggetto. Un altro fatto interessante è che Python implementa gli spazi dei nomi come dizionari. Esiste una mappatura nome-oggetto, con i nomi come chiavi e gli oggetti come valori. Più spazi dei nomi possono utilizzare lo stesso nome e mapparlo a un oggetto diverso. Ecco alcuni esempi di namespace:

  • Local Namespace: Questo spazio dei nomi include nomi locali all’interno di una funzione. Questo spazio dei nomi viene creato quando viene chiamata una funzione e dura solo fino al ritorno della funzione.
  • Spazio dei nomi globale: questo spazio dei nomi include i nomi di vari moduli importati che si stanno utilizzando in un progetto. Viene creato quando il modulo è incluso nel progetto e dura fino alla fine dello script.
  • Spazio dei nomi incorporato: questo spazio dei nomi include funzioni integrate e nomi di eccezioni incorporati.

Nella serie Mathematical Modules in Python su Envato Tuts+, ho scritto di utili funzioni matematiche disponibili in diversi moduli. Ad esempio, i moduli math e cmath hanno molte funzioni comuni a entrambi, come log10()acos()cos()exp(), ecc. Se si utilizzano entrambi questi moduli nello stesso programma, l’unico modo per utilizzare queste funzioni in modo inequivocabile è prefiggerle con il nome del modulo, come math.log10() e cmath.log10().

Che cos’è l’ambito?

Gli spazi dei nomi ci aiutano a identificare in modo univoco tutti i nomi all’interno di un programma. Tuttavia, questo non implica che possiamo usare un nome di variabile ovunque vogliamo. Un nome ha anche un ambito che definisce le parti del programma in cui è possibile utilizzare quel nome senza utilizzare alcun prefisso. Proprio come gli spazi dei nomi, ci sono anche più ambiti in un programma. Ecco un elenco di alcuni ambiti che possono esistere durante l’esecuzione di un programma.

  • Un ambito locale, che è l’ambito più interno che contiene un elenco di nomi locali disponibili nella funzione corrente.
  • Un ambito di tutte le funzioni che racchiudono. La ricerca di un nome inizia dall’ambito di chiusura più vicino e si sposta verso l’esterno.
  • Un ambito a livello di modulo che contiene tutti i nomi globali del modulo corrente.
  • L’ambito più esterno che contiene un elenco di tutti i nomi incorporati. Questo ambito viene cercato per ultimo per trovare il nome a cui hai fatto riferimento.

Nelle prossime sezioni di questo tutorial, useremo ampiamente la funzione Python dir() integrata per restituire un elenco di nomi nell’ambito locale corrente. Questo ti aiuterà a capire più chiaramente il concetto di namespace e scope.

Risoluzione dell’ambito

Come ho detto nella sezione precedente, la ricerca di un determinato nome inizia dalla funzione più interna e poi si sposta sempre più in alto fino a quando il programma può mappare quel nome a un oggetto. Quando nessun nome di questo tipo viene trovato in nessuno degli spazi dei nomi, il programma genera un’eccezione NameError.

Prima di iniziare, prova a digitaredir() in IDLE o in qualsiasi altro IDE Python.

dir()# 

Vediamo l’output della funzione dir() dopo aver definito una variabile e una funzione.

a_num = 10dir()# def some_func(): b_num = 11 print(dir()) some_func()# dir()# 

La funzionedir() emette solo l’elenco dei nomi all’interno dell’ambito corrente. Ecco perché all’interno dell’ambito di some_func(), c’è solo un nome chiamato b_num. Chiamando dir()dopo aver definitosome_func() lo aggiunge all’elenco dei nomi disponibili nello spazio dei nomi globale.

Ora, vediamo l’elenco dei nomi all’interno di alcune funzioni nidificate. Il codice in questo blocco continua dal blocco precedente.

Il codice precedente definisce due variabili e una funzione all’interno dell’ambito diouter_func(). All’interno di inner_func(), la funzione dir() stampa solo il nome d_num. Questo sembra giusto in quantod_num è l’unica variabile definita lì.

Se non specificato esplicitamente utilizzandoglobal, riassegnando un nome globale all’interno di uno spazio dei nomi locale si crea una nuova variabile locale con lo stesso nome. Questo è evidente dal seguente codice.

All’interno di entrambi iouter_func() einner_func()a_num è stato dichiarato come una variabile globale. Stiamo solo impostando un valore diverso per la stessa variabile globale. Questo è il motivo per cui il valore di a_num in tutte le posizioni è 20. D’altra parte, ogni funzione crea la propria variabile b_num con un ambito locale e la funzione print() stampa il valore di questa variabile con ambito locale.

Importare correttamente i moduli

È molto comune importare moduli esterni nei tuoi progetti per accelerare lo sviluppo. Esistono tre diversi modi per importare i moduli. In questa sezione, imparerai a conoscere tutti questi metodi, discutendo i loro pro e contro in dettaglio.

  • from module import *: Questo metodo di importazione di un modulo importa tutti i nomi dal modulo specificato direttamente nello spazio dei nomi corrente. Si potrebbe essere tentati di utilizzare questo metodo perché consente di utilizzare una funzione direttamente senza aggiungere il nome del modulo come prefisso. Tuttavia, è molto soggetto a errori e si perde anche la capacità di dire quale modulo ha effettivamente importato quella funzione. Ecco un esempio di utilizzo di questo metodo:

Se hai familiarità con i moduli math e cmath, sai già che ci sono alcuni nomi comuni che sono definiti in entrambi questi moduli ma si applicano rispettivamente ai numeri reali e complessi.

Poiché abbiamo importato il modulo cmath dopo il modulo math, sovrascrive le definizioni di funzione di queste funzioni comuni dal modulo math. Questo è il motivo per cui il primo log10(125) restituisce un numero reale e il secondo log10(125) restituisce un numero complesso. Non è possibile utilizzare la funzione log10() dal modulo matematico ora. Anche se hai provato a digitare math.log10(125), otterrai un’eccezione NameError perché math non esiste effettivamente nello spazio dei nomi.

La linea di fondo è che non dovresti usare questo modo di importare funzioni da moduli diversi solo per salvare alcune sequenze di tasti.

  • from module import nameA, nameB: Se sai che userai solo uno o due nomi da un modulo, puoi importarli direttamente usando questo metodo. In questo modo, puoi scrivere il codice in modo più conciso mantenendo al minimo l’inquinamento dello spazio dei nomi. Tuttavia, tieni presente che non puoi ancora usare nessun altro nome dal modulo usando module.nameZ. Qualsiasi funzione che ha lo stesso nome nel tuo programma sovrascriverà anche la definizione di quella funzione importata dal modulo. Ciò renderà inutilizzabile la funzione importata. Ecco un esempio di utilizzo di questo metodo:
dir()# from math import log2, log10dir()# log10(125)# 2.0969100130080562
  • import module: Questo è il modo più sicuro e consigliato per importare un modulo. L’unico inconveniente è che dovrai anteporre il nome del modulo a tutti i nomi che utilizzerai nel programma. Tuttavia, sarà possibile evitare l’inquinamento dello spazio dei nomi e definire anche funzioni i cui nomi corrispondono al nome delle funzioni dal modulo.
dir()# import mathdir()# math.log10(125)# 2.0969100130080562

Considerazioni finali

Spero che questo tutorial ti abbia aiutato a capire gli spazi dei nomi e la loro importanza. Ora dovresti essere in grado di determinare l’ambito di nomi diversi in un programma ed evitare potenziali insidie.

Inoltre, non esitate a vedere ciò che abbiamo a disposizione per la vendita e per lo studio sul mercato, e non esitate a fare domande e fornire il vostro prezioso feedback utilizzando il feed qui sotto.

La sezione finale dell’articolo ha discusso diversi modi di importare moduli in Python e i pro ei contro di ciascuno di essi. Se avete domande relative a questo argomento, per favore fatemelo sapere nei commenti.

Imparare Python

Imparare Python con la nostra guida completa python tutorial, se siete appena iniziato o sei un programmatore esperto in cerca di imparare nuove abilità.