python - para - tutorial de django
Espacios de nombres con importación de módulos (5)
"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
.
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 <module>
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 <function cool at 0x02B11AF0>
. Por lo tanto, ya que cool
está dentro del espacio de nombres global del módulo principal, el programa 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 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
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 <module>
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
.
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.
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 programa 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