Espacios de nombres con importación de módulos

Estoy aprendiendo Python y todavía soy un principiante, aunque lo he estado estudiando durante aproximadamente un año. Estoy tratando de escribir un módulo de funciones que se llama dentro de un módulo principal. Cada una de las funciones en el módulo llamado necesita el módulo matemático para ejecutarse. Me pregunto si hay una manera de hacerlo sin importar el módulo matemático dentro del módulo llamado. Esto es lo que tengo:

main.py :

 from math import * import module1 def wow(): print pi wow() module1.cool() 

module1.py :

 def cool(): print pi 

Al ejecutar main.py me sale:

 3.14159265359 Traceback (most recent call last): File "Z:\Python\main.py", line 10, in  module1.cool() File "Z:\Python\module1.py", line 3, in cool print pi NameError: global name 'pi' is not defined 

Lo que me cuesta entender es por qué me sale un error de nombre al ejecutar main.py Sé que la variable pi convierte en global para el módulo principal al importar porque wow puede acceder a ella. También sé que cool convierte en global para el módulo principal al importar porque puedo imprimir module1.cool y obtener . Por lo tanto, ya que cool está dentro del espacio de nombres global del módulo principal, el progtwig no debería buscar primero la función cool para la variable pi , y luego, cuando no la encuentra allí, busque la variable pi en el módulo main y busque allí?

La única forma de module1.py esto que conozco es importar el módulo matemático dentro de module1.py . No me gusta la idea de eso, sin embargo, porque hace las cosas más complicadas y soy un fanático del código simple y agradable. Siento que estoy cerca de comprender los espacios de nombres, pero necesito ayuda en este caso. Gracias.

Como muestra el main.py , el problema no está en main.py , sino en module1.py :

 Traceback (most recent call last): File "Z:\Python\main.py", line 10, in  module1.cool() File "Z:\Python\module1.py", line 3, in cool print pi NameError: global name 'pi' is not defined 

En otras palabras, en el module1 , no hay un nombre global pi , porque no lo has importado allí. Cuando lo hace from math import * en main.py , eso solo importa todo del espacio de nombres del módulo math al espacio de nombres del módulo main , no al espacio de nombres de cada módulo.

Creo que la clave que falta aquí es que cada módulo tiene su propio espacio de nombres “global”. Esto puede ser un poco confuso al principio, porque en idiomas como C, hay un único espacio de nombres global compartido por todas las variables y funciones extern . Pero una vez que superas esa suposición, el modo Python tiene perfecto sentido.

Por lo tanto, si desea utilizar pi desde el module1 , debe realizar la from math import * en el module1.py . (O podría encontrar otra forma de inyectarlo; por ejemplo, module1.py podría hacerlo from main import * , o main.py podría hacer module1.pi = pi , etc. O podría meter a pi en las builtins mágicas / __builtin__ Módulo, o usa otros trucos. Pero la solución obvia es hacer la import donde quieras que se importe.)


Como nota al margen, normalmente no desea hacerlo from foo import * cualquier lugar, excepto el intérprete interactivo o, ocasionalmente, el script de nivel superior. Hay excepciones (por ejemplo, algunos módulos están diseñados explícitamente para ser utilizados de esa manera), pero la regla de oro es import foo o usar una from foo import bar, baz limitada from foo import bar, baz .

“Explícito es mejor que implícito” es una decisión de diseño que tomaron los creadores de Python (inicie Python y ejecute la import this ).

Por lo tanto, cuando ejecutas module1.cool() , Python no buscará la pi indefinida en el módulo main .


Tendrá que importar el módulo matemático explícitamente cada vez que quiera usarlo, así es como funciona Python.

Además, debes evitar las from X import * estilo from X import * , eso también es una mala práctica. Aquí, podrías hacer: from math import pi .

Como han dicho otros, en realidad no hay un pi global en su module1 . Una buena solución para usted es esta, que solo importa pi una vez de math y asegura explícitamente que la pi que está obteniendo es la del module1 :

main.py :

 import module1 def wow(): print module1.pi wow() module1.cool() 

module1.py :

 from math import pi def cool(): print pi 

El enfoque simple de exec (python 3) o execfile (python 2) como se menciona en los comentarios de @abarnert puede ser útil para algunos flujos de trabajo. Todo lo que se necesita es reemplazar la línea de importación con:

 exec( open("module1.py").read() ) # python 3 

y luego puede simplemente llamar a la función con cool() lugar de module1.cool() . En cool() , la variable pi se comportará como un global, como originalmente había esperado el OP.

En pocas palabras, esto es simplemente ocultar una definición de función que, de lo contrario, aparecería en la parte superior de su progtwig principal y tiene ventajas y desventajas. Para proyectos grandes con múltiples módulos e importaciones, el uso de exec (en lugar de un espacio de nombres adecuado) es probablemente un error, ya que generalmente no quiere mantener demasiadas cosas dentro de un solo espacio de nombres global.

Pero para casos simples (como usar Python como un script de shell), exec le brinda una forma simple y concisa de ocultar las funciones compartidas mientras les permite compartir el espacio de nombres global. Solo tenga en cuenta que en este caso es posible que desee reflexionar sobre cómo nombra sus funciones (por ejemplo, use v1_cool y v2_cool para realizar un seguimiento de las diferentes versiones, ya que no puede hacer v1.cool y v2.cool ).

Una desventaja menos obvia de usar exec aquí es que los errores en el código ejecutado pueden no mostrar el número de línea del error, aunque puede solucionar esto: cómo obtener el número de línea de un error de exec o execfile en Python

Dentro del módulo, simplemente puede definir from math import pi , que solo importaría pi desde math pero no desde el módulo math completo.