2010-10-11 26 views
8

main.py:Python: ¿por qué un módulo importado no puede hacer referencia a otro módulo importado?

import subone 
import subtwo 

subone.py:

a = 'abc' 

subtwo.py:

print subone.a 

Correr python main.py lanza una NameError: name 'subone' is not defined. Esperaba que imprimiera 'abc'.

Refactorizando que utilice fromimport y las clases no ayuda:

main.py:

from subone import * # Only using from X import * for example purposes. 
from subtwo import * 

print 'from main.py:', a.out 

subone.py:

class A: 
    out = 'def' 

a = A() 

SubTwo. py:

# This throws NameError: name 'a' is not defined 
print a.out 

# This throws NameError: name 'A' is not defined 
b = A() 
print b.out 

PERO se imprimir 'desde main.py: def'. (Funciona al usar import también.)

¿Por qué funciona de esta manera? Parece que una vez importado subone, debe estar disponible para subtwo.

¿Es porque es una mala programación que los módulos importados dependan unos de otros sin pasar por su módulo "principal"? ¿Hay alguna otra manera estándar de hacer esto?

Actualización:

ahora entiendo que el primer ejemplo no funcionará porque la línea print subone.a no reconoce el nombre subone, no estar en subtwo 's espacio de nombres (aunque sea en main.py' s), y se está llamando desde el módulo subtwo. Esto se puede solucionar usando import subone en la parte superior de subtwo.py - no volverá a cargar el módulo sino que lo agregará al espacio de nombre subtwo para que subtwo pueda usarlo.

Pero qué pasa con esto:

main.py:

from subone import Nugget 
from subtwo import Wrap 

wrap = Wrap() 
print wrap.nugget.gold 

subone.py:

class Nugget: 
    gold = 'def' 

SubTwo.PY:

class Wrap: 
    nugget = Nugget() 

yo creo que desde Wrap y Nugget son ambos cargaron directamente en main 'espacio de nombres s, que utilizarían main' s espacio de nombres y ser capaz de hacer referencia entre sí, pero arroja una NameError: name 'Nugget' is not defined. ¿ESTOY porque Wrap se evalúa/comprueba desde dentro del espacio de nombresubtwo ANTES de cargarse en el espacio de nombre main?

+4

Su encapsulación parece realmente roto ... – Daenyth

+0

necesita buscar ámbito léxico. La idea básica es que el código tiene acceso a lo que puede 'ver' en el código fuente. lo que sucede en el tiempo de ejecución no tiene nada que ver con eso. – aaronasterling

Respuesta

6

Si ha modificado el subtwo.py esta manera, funcionará

import subone 
print subone.a 

Al hacer subone.a en subtwo.py, que está tratando de acceder al espacio de nombres en subone subtwo.py y en el espacio de nombres "subone", debería haber un atributo "a".

Cuando lo haga, importe subone en subtwo.py, luego subone se agrega al espacio de nombres y el espacio de nombres subone tiene el atributo a. así subone.a funcionará.

También le sugiero que juegue con dir() para ver cómo se agregan los espacios de nombres.

In subtwo.py, puede hacer lo siguiente:

print dir() 
import subone 
print dir() 
print subone.a 

Del mismo modo, trate de añadir "dir de impresión()" antes y después de sus declaraciones de importación y la idea debería ser claro para usted.

"importar x", añade 'x' para los módulos actuales espacio de nombres, mientras que "de x import *" se añadir todo el nivel de módulo atributos directamente en espacio de nombres de módulo actual

Así que en el primer ejemplo anterior de main.py, subone.py y subtwo.py, el espacio de nombres en main.py contendrá 'subone' y 'subtwo', mientras que subtwo.py tendrá un espacio de nombre vacío y no podrá acceder a subone.a.

[Editar: Algunas explicaciones más] considerar siguientes archivos: main.py

print "Before importing subone : ", dir() 
import subone 
print "After importing subone and before importing subtwo: ", dir() 
import subtwo 
print "After importing subone and subtwo: ", dir() 

subone.py

a = 'abc' 

subtwo.py

print dir() 
import subone 
print "module level print: ", subone.a 
print dir() 
def printX(): 
    print subone.a 

Y el salida de ejecución main.py:

Before importing subone : ['__builtins__', '__doc__', '__file__', '__name__', '__package__'] 
After importing subone and before importing subtwo: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone'] 
['__builtins__', '__doc__', '__file__', '__name__', '__package__'] 
module level print: abc 
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone'] 
After importing subone and subtwo: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone', 'subtwo'] 

Algunas observaciones

  1. se puede observar que la importación de un módulo de subtwo.py, la declaración de impresión se ejecuta inmediatamente.
  2. Por lo tanto, cuando subone y subtwo se importan en main.py, se aumenta el espacio de nombres de main.py.
  3. Eso no significa que se aumentará el espacio de nombres de subtwo. entonces "a" solo está disponible en main.py vía subone.a
  4. Cuando importamos subone en subtwo.py, el espacio de nombres de subtwo se aumenta con subone y el atributo a de subdominio de módulo está disponible en subtow.py vía subone .a
+0

Esto es muy útil. dir() realmente me deja las cosas claras. Mi única pregunta (como comenté a continuación) es que si "from x import *" agrega todos los atributos de nivel de módulo directamente en el espacio de nombres actual, ¿por qué no pueden esos atributos tener acceso el uno al otro? –

+1

Esa importación en realidad no cambia el alcance de los atributos, simplemente copia su definición al alcance local. –

+0

@willell: Ignacio Vazquez-Abrams tiene razón. Debería haber sido más claro. Esto no es lo mismo que copiar el código como ocurre en el caso de #include en "C". Los módulos importados ya están cargados y evaluados. si tenía una declaración impresa en un módulo importado, ya habría sido evaluada. – pyfunc

2

El espacio de nombres subtwo estará totalmente vacío a menos que importe subone en él.

En cuanto a las prácticas de programación, subone y subtwo puede depender el uno del otro si así se desea, sólo tiene que vincular explícitamente (con un import)

+0

Está bien, pero ¿por qué no funciona incluso cuando se usa from-import, que carga todo en el espacio de nombres de main? –

+2

No importa, cuando 'subtwo' se ejecuta (cuando lo 'import' principal), nada está en * its * namespace. –

+1

Podría ser útil recordar que 'import' en Python no es como' include' en otros idiomas. –

3

Puede explicar por qué sentir como subone debe estar disponible para subtwo, cuando subone ha sido importado por main? Tal como está, subtwo.py se puede compilar sin saber qué main.py ha importado.

Además, si un segundo programa importa subtwo.py, ¿el conocimiento de subtwo de subtwo depende de cuál de los dos programas principales está importando subtwo? Esto reduciría la reutilización de subtwo.

Parece que estás pensando en la compilación como un proceso con un orden definido, que acumula información de estado: compila main.py, durante el cual compilamos/importamos subone.py, acumulamos información de él, y luego compilamos/import subtwo.py, usando la información que ya hemos acumulado.

En su lugar, la compilación de cada módulo es independiente de otros, a menos que se declaren las dependencias. Esto hace que sea mucho más fácil reutilizar y mantener el código: hay menos dependencias ocultas.

¿Es porque es una mala programación de los módulos han importado dependerá de cada otra sin tener que pasar a través de su módulo de 'padre'?

No como tal ... Es sólo una mala programación de tener el módulo 2 depende de módulo 1 sin decirlo, es decir, sin el módulo 2 se declara "Dependo de módulo 1".

+1

Ah, ya veo. La forma en que lo describes ayuda. Creo que he estado acostumbrado a las declaraciones 'include' y' require' de PHP, que incrustan código directamente. En cambio, los módulos son objetos que necesitan ser llamados. –

+1

@willell: nunca he usado PHP, pero C es similar con el preprocesador '# include' simplemente pegando todo el archivo allí. De todos modos, algún tipo de dependencia implícita como esa simplemente no parece inteligente, independientemente del idioma. –

+0

@willell, eso tiene sentido ... la forma en que estás pensando de hecho coincide con la forma en que PHP y C incluyen mecanismos que funcionan. Sin embargo, puede ver cómo eso conduce a dependencias que son difíciles de rastrear ... para averiguar de qué archivo depende B, debe buscar todos los lugares donde se incluye el archivo B. Entonces, hay una diferencia fundamental entre "incluir un archivo" e "importar un módulo". El primero es más una inserción simple y literal de una cadena de texto, inconsciente de las consecuencias semánticas. Este último es más un enlace conceptual de un componente de programa a otro. – LarsH

0

En cuanto a su segundo ejemplo, "main.py" sabe acerca de Nugget pero "subtwo.py" no.

Creo que ayudaría a pensar de esta manera. Cada módulo (archivo) tiene que funcionar como si los únicos otros módulos que existen son los que importa. En este caso, "subtwo.py" no podría ejecutarse solo porque no ha importado Nugget. Esencialmente "subtwo.py" no sabe lo que "main.py" sabe. No debería, porque cualquier persona podría llamarlo desde cualquier lugar, y no puede depender de que nadie más importe lo que necesita.

0

Esto se debe a que los módulos importados tienen sus propios espacios de nombres separados.Lo que ha escrito es muy parecido:

def func1(): 
    a = 1 

def func2(): 
    print a 

func1() 
func2() # This will throw an error 

a = 2 

func2() # Now this will print 2. 

Los módulos tienen sus espacios de nombres local, y cuando se utiliza from subone import * que importe el espacio SOLAMENTE a main.py espacio de nombres que no se puede acceder por subtwo.

Sin embargo, lo que estás tratando de hacer es una muy mala práctica. Evita el uso de variables globales y import *, simplemente porque te sentirás cada vez más confundido como ahora.


Más en él: https://docs.python.org/3/reference/import.html

https://bytebaker.com/2008/07/30/python-namespaces/

http://www.diveintopython.net/html_processing/locals_and_globals.html

y tal vez: http://sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html

Cuestiones relacionadas