I conflitti di nome si verificano sempre nella vita reale. Ad esempio, ogni scuola in cui sono andato ha avuto almeno due studenti della mia classe che condividevano lo stesso nome. Se qualcuno entrava in classe e chiedeva lo studente X, chiedevamo con entusiasmo: "Di quale dei due stai parlando? Ci sono due studenti di nome X." Dopodiché, l'inquisitore ci avrebbe dato un cognome e lo avremmo presentato alla X giusta.
Tutta questa confusione e il processo per determinare la persona esatta di cui stiamo parlando cercando altre informazioni oltre a un nome potrebbero essere evitate se tutti avessero un nome univoco. Questo non è un problema in una classe di 30 studenti. Tuttavia, diventerà sempre più difficile trovare un unico, significativo e facile da ricordare nome per ogni bambino in una scuola, città, città, paese o nel mondo intero. Un altro problema nel fornire ad ogni bambino un nome univoco è che il processo per determinare se qualcun altro ha anche chiamato il loro bambino Macey, Maci o Macie potrebbe essere molto stancante.
Un conflitto molto simile può sorgere anche nella programmazione. Quando stai scrivendo un programma di sole 30 righe senza dipendenze esterne, è molto facile dare nomi univoci e significativi a tutte le tue 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.
Un namespace è fondamentalmente un sistema per assicurarsi che tutti i nomi di un programma siano unici e possano essere utilizzati senza alcun conflitto. Potresti già sapere che tutto in stringhe, liste, funzioni, ecc. In Python è 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 usare lo stesso nome e mapparlo su un oggetto diverso. Ecco alcuni esempi di spazi dei nomi:
Nei Mathematical Modules in Python series su Envato Tuts +, ho scritto sulle funzioni matematiche utili disponibili in diversi moduli. Ad esempio, i moduli matematico e cmath hanno un sacco di funzioni che sono comuni a entrambi, come log10 ()
, acos ()
, cos ()
, exp ()
, ecc. Se stai usando entrambi questi moduli nello stesso programma, l'unico modo per usare queste funzioni in modo non ambiguo è prefisso con il nome del modulo, come math.log10 ()
e cmath.log10 ()
.
I namespace 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.
Nelle prossime sezioni di questo tutorial, utilizzeremo estensivamente la funzione incorporata di Python dir () per restituire un elenco di nomi nell'attuale ambito locale. Questo ti aiuterà a capire meglio il concetto di namespace e scope.
Come ho accennato nella sezione precedente, la ricerca di un nome dato inizia dalla funzione più interna e quindi si sposta sempre più in alto finché il programma non può mappare quel nome su un oggetto. Quando nessun nome viene trovato in nessuno degli spazi dei nomi, il programma alza a NameError eccezione.
Prima di iniziare, prova a digitare dir ()
in IDLE o qualsiasi altro IDE Python.
dir () # ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
Tutti questi nomi elencati da dir ()
sono disponibili in ogni programma Python. Per brevità, inizierò a riferirmi a loro come '__builtins __' ... '__spec__'
nel resto degli esempi.
Vediamo l'output di dir ()
funzione dopo aver definito una variabile e una funzione.
a_num = 10 dir () # ['__builtins __' ... '__spec__', 'a_num'] def some_func (): b_num = 11 print (dir ()) some_func () # ['b_num'] dir () # ['__builtins__ '...' __spec__ ',' a_num ',' some_func ']
Il dir ()
funzione restituisce solo l'elenco di nomi all'interno dello scope corrente. Ecco perché all'interno dello scopo di some_func ()
, c'è solo un nome chiamato b_num
. chiamata dir ()
dopo aver definito some_func ()
lo aggiunge all'elenco di nomi disponibili nello spazio dei nomi globale.
Ora, vediamo l'elenco dei nomi all'interno di alcune funzioni annidate. Il codice in questo blocco continua dal blocco precedente.
def outer_func (): c_num = 12 def inner_func (): d_num = 13 print (dir (), '- names in inner_func') e_num = 14 inner_func () print (dir (), '- names in outer_func') outer_func ( ) # ['d_num'] - nomi in inner_func # ['c_num', 'e_num', 'inner_func'] - nomi in outer_func
Il codice precedente definisce due variabili e una funzione nell'ambito di outer_func ()
. Dentro inner_func ()
, il dir ()
la funzione stampa solo il nome d_num
. Questo sembra giusto d_num
è l'unica variabile definita in là.
Se non specificato esplicitamente utilizzando globale
, la riassegnazione di un nome globale all'interno di uno spazio dei nomi locale crea una nuova variabile locale con lo stesso nome. Questo è evidente dal seguente codice.
a_num = 10 b_num = 11 def outer_func (): globale a_num a_num = 15 b_num = 16 def inner_func (): globale a_num a_num = 20 b_num = 21 stampa ('a_num inside inner_func:', a_num) print ('b_num inside inner_func: ', b_num) inner_func () print (' a_num inside external_func: ', a_num) print (' b_num inside outer_func: ', b_num) outer_func () print (' a_num outside all functions: ', a_num) print (' b_num outside all funzioni: ', b_num) # a_num inside inner_func: 20 # b_num inside inner_func: 21 # a_num inside external_func: 20 # b_num inside outer_func: 16 # a_num al di fuori di tutte le funzioni: 20 # b_num al di fuori di tutte le funzioni: 11
All'interno di entrambi outer_func ()
e inner_func ()
, a_num
è stato dichiarato di essere una variabile globale. Stiamo semplicemente impostando un valore diverso per la stessa variabile globale. Questa è la ragione per cui il valore di a_num
in tutte le località è 20. D'altra parte, ogni funzione crea il proprio b_num
variabile con un ambito locale e il stampare()
funzione stampa il valore di questa variabile localmente applicata.
È molto comune importare moduli esterni nei progetti per accelerare lo sviluppo. Esistono tre diversi modi di importare i moduli. In questa sezione, imparerai tutti questi metodi, discutendo dettagliatamente i loro pro e contro.
dall'importazione del modulo *
: Questo metodo di importazione di un modulo importa tutti i nomi dal modulo specificato direttamente nel tuo spazio dei nomi corrente. Potresti essere tentato di utilizzare questo metodo perché consente di utilizzare direttamente una funzione senza aggiungere il nome del modulo come prefisso. Tuttavia, è molto soggetto a errori e si perde anche la capacità di stabilire quale modulo abbia effettivamente importato quella funzione. Ecco un esempio di utilizzo di questo metodo:dir () # ['__builtins __' ... '__spec__'] dall'importazione matematica * dir () # ['__builtins __' ... '__spec__', 'acos', 'acosh', 'asin', 'asinh', # 'atan' , 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'gradi', # 'e', 'erf', 'erfc', 'exp', 'expm1', "fabs", "factorial", "floor", "fmod", # "frexp", "fsum", "gamma", "gcd", "hypot", "inf", "isclose", "isfinite", # 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', # 'modf', 'nan', 'pi', 'pow', ' radians ',' sin ',' sinh ',' sqrt ',' tan ', #' tanh ',' trunc '] log10 (125) # 2.0969100130080562 da cmath import * dir () # [' __builtins __ '...' __spec__ ' , "aco", "acosh", "asin", "asinh", "atan", "atan2", "atanh", "ceil", "copysign", "cos", "cosh", "gradi", 'e', 'erf', # 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', # 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', # 'ldexp', 'lgamma', 'log', 'log10', 'log1p', ' log2 ',' modf ',' nan ',' phase ', #' pi ',' polar ',' pow ',' radians ',' re ct ',' sin ',' sinh ',' sqrt ',' tan ',' tanh ', #' trunc '] log10 (125) # (2.0969100130080562 + 0j)
Se conosci il matematica e cmath moduli, sai già che ci sono alcuni nomi comuni che sono definiti in entrambi questi moduli, ma si applicano rispettivamente a numeri reali e complessi.
Dal momento che abbiamo importato il cmath modulo dopo il matematica modulo, sovrascrive le definizioni delle funzioni di queste funzioni comuni dal matematica modulo. Questo è il motivo per cui il primo log10 (125)
restituisce un numero reale e il secondo log10 (125)
restituisce un numero complesso. Non c'è modo per te di usare il log10 ()
funzione dal modulo matematico ora. Anche se hai provato a digitare math.log10 (125)
, otterrai un'eccezione NameError perché matematica
in realtà non esiste nello spazio dei nomi.
La linea di fondo è che non si dovrebbe usare questo modo di importare le funzioni da diversi moduli solo per risparmiare alcune sequenze di tasti.
dal nome di importazione del modulo A, nomeB
: Se sai che utilizzerai solo uno o due nomi da un modulo, puoi importarli direttamente usando questo metodo. In questo modo, è possibile scrivere il codice in modo più conciso mantenendo comunque l'inquinamento dello spazio dei nomi al minimo. Tuttavia, tieni presente che non puoi ancora utilizzare nessun altro nome dal modulo usando module.nameZ
. Qualsiasi funzione che abbia lo stesso nome nel programma sovrascriverà anche la definizione di quella funzione importata dal modulo. Ciò renderà la funzione importata inutilizzabile. Ecco un esempio di utilizzo di questo metodo:dir () # ['__builtins __' ... '__spec__'] da math import log2, log10 dir () # ['__builtins __' ... '__spec__', 'log10', 'log2'] log10 (125) # 2.0969100130080562
modulo di importazione
: Questo è il modo più sicuro e consigliato per importare un modulo. L'unico svantaggio è che dovrai anteporre il nome del modulo a tutti i nomi che utilizzerai nel programma. Tuttavia, sarete in grado di evitare l'inquinamento dello spazio dei nomi e definire anche le funzioni i cui nomi corrispondono al nome delle funzioni del modulo.dir () # ['__builtins __' ... '__spec__'] import math dir () # ['__builtins __' ... '__spec__', 'math'] math.log10 (125) # 2.0969100130080562
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 esitare a vedere ciò che abbiamo a disposizione per la vendita e per studiare nel mercato, e non esitare a fare domande e fornire il tuo prezioso feedback utilizzando il feed qui sotto.
La sezione finale dell'articolo trattava diversi modi di importare i moduli in Python e i pro e i contro di ciascuno di essi. Se avete domande relative a questo argomento, fatemelo sapere nei commenti.
Impara Python con la nostra guida completa al tutorial su Python, sia che tu stia appena iniziando o che sei un programmatore esperto che cerca di imparare nuove abilità.