¿Qué son los espacios de nombres de Python (y por qué se necesitan?)

Los conflictos de nombres ocurren todo el tiempo en la vida real. Por ejemplo, todas las escuelas a las que asistí tenían al menos dos estudiantes en mi clase que compartían el mismo nombre. Si alguien entrara a la clase y preguntara por el estudiante X, le preguntamos con entusiasmo: "¿De cuál de ellos está hablando? Hay dos estudiantes llamados X". Después de eso, la persona indagante nos daría un apellido, y le presentaríamos la X correcta..

Toda esta confusión y el proceso de determinar la persona exacta de la que estamos hablando al buscar otra información, además del nombre, podrían evitarse si todos tuviéramos un nombre único. Esto no es un problema en una clase de 30 estudiantes. Sin embargo, será cada vez más difícil encontrar un único, significativo y Fácil de recordar nombre para cada niño en una escuela, pueblo, ciudad, país o el mundo entero. Otro problema al proporcionar a cada niño un nombre único es que el proceso de determinar si otra persona también ha nombrado a su hijo Macey, Maci o Macie podría ser muy agotador.

Un conflicto muy similar también puede surgir en la programación. Cuando está escribiendo un programa de solo 30 líneas sin dependencias externas, es muy fácil dar nombres únicos y significativos a todas sus variables. El problema surge cuando hay miles de líneas en un programa y también ha cargado algunos módulos externos. En este tutorial, aprenderá sobre los espacios de nombres, su importancia y la resolución de alcance en Python. 

¿Qué son los espacios de nombres?

Un espacio de nombres es básicamente un sistema para garantizar que todos los nombres de un programa sean únicos y puedan usarse sin ningún conflicto. Es posible que ya sepa que todo en cadenas, listas, funciones, etc. similares a Python es un objeto. Otro hecho interesante es que Python implementa espacios de nombres como diccionarios. Existe una asignación de nombre a objeto, con los nombres como claves y los objetos como valores. Varios espacios de nombres pueden usar el mismo nombre y asignarlo a un objeto diferente. Aquí hay algunos ejemplos de espacios de nombres:

  • Espacio de nombres local: este espacio de nombres incluye nombres locales dentro de una función. Este espacio de nombres se crea cuando se llama a una función, y solo dura hasta que la función retorna.
  • Espacio de nombres global: este espacio de nombres incluye nombres de varios módulos importados que está utilizando en un proyecto. Se crea cuando el módulo se incluye en el proyecto y dura hasta que finaliza el script..
  • Espacio de nombres incorporado: este espacio de nombres incluye funciones integradas y nombres de excepción incorporados.

En la sección Módulos matemáticos en Python sobre Envato Tuts +, escribí sobre funciones matemáticas útiles disponibles en diferentes módulos. Por ejemplo, los módulos math y cmath tienen muchas funciones que son comunes a ambos, como log10 (), acos (), cos (), exp (), etc. Si está utilizando ambos de estos módulos en el mismo programa, la única forma de usar estas funciones de manera inequívoca es prefijarlos con el nombre del módulo, como math.log10 () y cmath.log10 ().

¿Qué es el alcance?

Los espacios de nombres nos ayudan a identificar de forma única todos los nombres dentro de un programa. Sin embargo, esto no implica que podamos usar un nombre de variable en cualquier lugar que queramos. Un nombre también tiene un alcance que define las partes del programa donde podría usar ese nombre sin usar ningún prefijo. Al igual que los espacios de nombres, también hay múltiples ámbitos en un programa. Aquí hay una lista de algunos ámbitos que pueden existir durante la ejecución de un programa..

  • Un ámbito local, que es el ámbito más interno que contiene una lista de nombres locales disponibles en la función actual.
  • Un ámbito de todas las funciones que lo encierran. La búsqueda de un nombre comienza desde el ámbito de cierre más cercano y se mueve hacia afuera.
  • Un ámbito de nivel de módulo que contiene todos los nombres globales del módulo actual.
  • El ámbito más externo que contiene una lista de todos los nombres incorporados. Este ámbito se busca en último lugar para encontrar el nombre al que hizo referencia. 

En las siguientes secciones de este tutorial, usaremos ampliamente la función direc. () De Python para devolver una lista de nombres en el ámbito local actual. Esto le ayudará a comprender el concepto de espacios de nombres y el alcance con mayor claridad..

Resolución de alcance

Como mencioné en la sección anterior, la búsqueda de un nombre dado comienza desde la función más interna y luego se mueve cada vez más alto hasta que el programa puede asignar ese nombre a un objeto. Cuando no se encuentra dicho nombre en ninguno de los espacios de nombres, el programa genera un NameError excepción.

Antes de comenzar, intente escribir dir () en IDLE o en cualquier otro IDE de Python.

dir () # ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

Todos estos nombres listados por dir () están disponibles en todos los programas de Python. En aras de la brevedad, empezaré a referirme a ellos como '__builtins __' ... '__spec__' en el resto de los ejemplos.

Veamos la salida de la dir () función después de definir una variable y una función.

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 '] 

los dir () La función solo genera la lista de nombres dentro del alcance actual. Es por eso que dentro del ámbito de some_func (), solo hay un nombre llamado b_num. Vocación dir () después de definir some_func () Lo agrega a la lista de nombres disponibles en el espacio de nombres global..

Ahora, veamos la lista de nombres dentro de algunas funciones anidadas. El código en este bloque continúa desde el bloque anterior..

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'] - nombres en inner_func # ['c_num', 'e_num', 'inner_func'] - nombres en outer_func

El código anterior define dos variables y una función dentro del alcance de exterior_func (). Dentro inner_func (), la dir () La función solo imprime el nombre d_num. Esto parece justo como d_num Es la única variable definida allí.

A menos que se especifique explícitamente utilizando global, la reasignación de un nombre global dentro de un espacio de nombres local crea una nueva variable local con el mismo nombre. Esto es evidente a partir del siguiente código..

a_num = 10 b_num = 11 def outer_func (): global a_num a_num = 15 b_num = 16 def inner_func (): global a_num a_num = 20 b_num = 21 print ('a_num inside inner_func:', a_num) print ('b_num inside inner_func: ', b_num) inner_func () imprimir (' a_num inside outer_func: ', a_num) imprimir (' b_num inside outer_func: ', b_num) outer_func () imprimir (' a_num fuera de todas las funciones: ', a_num) imprimir (' b_num fuera de todo funciones: ', b_num) # a_num inside inner_func: 20 # b_num inside inner_func: 21 # a_num inside outer_func: 20 # b_num inside outer_func: 16 # a_num fuera de todas las funciones: 20 # b_num fuera de todas las funciones: 11

Dentro de ambos exterior_func () y inner_func (), a_num ha sido declarado como una variable global. Solo estamos configurando un valor diferente para la misma variable global. Esta es la razón por la que el valor de a_num en todas las ubicaciones es 20. Por otro lado, cada función crea su propia b_num variable con un alcance local, y la impresión() La función imprime el valor de esta variable de ámbito local..

Importación adecuada de módulos

Es muy común importar módulos externos en sus proyectos para acelerar el desarrollo. Hay tres formas diferentes de importar módulos. En esta sección, aprenderá sobre todos estos métodos, discutiendo en detalle sus ventajas y desventajas..

  • desde el módulo de importación *: Este método de importar un módulo importa todos los nombres del módulo dado directamente en su espacio de nombres actual. Podría sentirse tentado a usar este método porque le permite usar una función directamente sin agregar el nombre del módulo como prefijo. Sin embargo, es muy propenso a errores, y también pierde la capacidad de indicar qué módulo realmente importó esa función. Aquí hay un ejemplo del uso de este método:
dir () # ['__builtins __' ... '__spec__'] from math import * dir () # ['__builtins __' ... '__spec__', 'acos', 'acosh', 'asin', 'asinh', # 'atan' , 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', # '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 de cmath import * dir () # [' __builtins __ '...' __spec__ ' , 'acos', 'acosh', 'asin', 'asinh', 'atan', # 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', '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)

Si está familiarizado con el mates y cmath módulos, ya sabe que hay algunos nombres comunes que están definidos en ambos módulos pero que se aplican a números reales y complejos respectivamente. 

Desde que hemos importado el cmath módulo después de la mates módulo, sobrescribe las definiciones de funciones de estas funciones comunes de la mates módulo. Por eso la primera log10 (125) Devuelve un número real y el segundo. log10 (125) devuelve un número complejo. No hay manera de que uses la log10 () Funcionar desde el módulo matemático ahora. Incluso si has intentado escribir math.log10 (125), obtendrá una excepción NameError porque mates no existe realmente en el espacio de nombres.

La conclusión es que no debe utilizar esta forma de importar funciones de diferentes módulos solo para guardar unas pocas pulsaciones de teclas..

  • desde el módulo importar nombre A, nombreB: Si sabe que solo va a utilizar uno o dos nombres de un módulo, puede importarlos directamente usando este método. De esta manera, puede escribir el código de manera más concisa y al mismo tiempo mantener la contaminación del espacio de nombres al mínimo. Sin embargo, tenga en cuenta que todavía no puede usar ningún otro nombre del módulo usando módulo.nombreZ. Cualquier función que tenga el mismo nombre en su programa también sobrescribirá la definición de esa función importada desde el módulo. Esto hará que la función importada quede inutilizable. Aquí hay un ejemplo del uso de este método:
dir () # ['__builtins __' ... '__spec__'] desde math import log2, log10 dir () # ['__builtins __'… '__spec__', 'log10', 'log2'] log10 (125) # 2.0969100130080562
  • módulo de importación: Esta es la forma más segura y recomendada de importar un módulo. El único inconveniente es que tendrá que prefijar el nombre del módulo a todos los nombres que va a utilizar en el programa. Sin embargo, podrá evitar la contaminación del espacio de nombres y también definir funciones cuyos nombres coincidan con el nombre de las funciones del módulo..
dir () # ['__builtins __' ... '__spec__'] import math dir () # ['__builtins __'… '__spec__', 'math'] math.log10 (125) # 2.0969100130080562

Pensamientos finales

Espero que este tutorial te haya ayudado a entender los espacios de nombres y su importancia. Ahora debería poder determinar el alcance de los diferentes nombres en un programa y evitar los peligros potenciales. 

Además, no dude en ver lo que tenemos disponible para la venta y para estudiar en el mercado, y no dude en hacer cualquier pregunta y proporcionar sus valiosos comentarios utilizando la siguiente información..

La sección final del artículo trata sobre las diferentes formas de importar módulos en Python y las ventajas y desventajas de cada uno de ellos. Si tiene alguna pregunta relacionada con este tema, hágamelo saber en los comentarios..

Aprender Python

Aprende Python con nuestra completa guía de tutoriales de Python, ya sea que estés empezando o seas un programador experimentado que busca aprender nuevas habilidades..