2012-07-28 7 views
33

que tienen un módulo de botella servidor web con la siguiente línea:Dos módulos de Python requieren el contenido del otro, ¿puede funcionar?

from foobar.formtools import auto_process_form_insert 

y el módulo foobar.formtools contiene esta línea:

from foobar.webserver import redirect, redirect_back 

Por supuesto, ambas se obtienen los siguientes errores (respectivamente):

ImportError: cannot import name auto_process_form_insert
ImportError: cannot import name redirect

Es simplemente un hecho que en Python dos módulos no pueden importarse entre sí y todas las importaciones de módulos deben ser jerárquicas al en la naturaleza, o estoy haciendo algo mal? Alternativamente, ¿hay alguna solución alternativa para colocar todas estas bonitas funciones en los nuevos módulos?

+3

Como se explica en mi respuesta, es posible que los módulos se importen entre sí, pero si necesita hacerlo, puede que desee reconsiderar su diseño. – icktoofay

+0

Creo que esta explicación es mucho más fácil de entender: http://stackoverflow.com/questions/9642451/python-files-import-from-each-other – rizkiaditya24

Respuesta

42

Los módulos pueden se importan cíclicamente entre sí, pero hay una trampa. En el caso simple, debería funcionar moviendo las declaraciones import al final del archivo o no usando la sintaxis from.

He aquí por qué esto funciona:

Al importar un módulo, Python comprueba primero sys.modules. Si está allí, simplemente importa desde allí. Si no está allí, intenta importarlo de la manera normal; básicamente, encuentra el archivo y ejecuta las cosas en él.

Al ejecutar un módulo se rellena el contenido del módulo. Por ejemplo, digamos que tenemos este módulo, de manera creativa nombrado example_opener:

import webbrowser 

def open_example(): 
    webbrowser.open('http://www.example.com/') 

Al inicio, el módulo está vacía. Luego ejecuta Python:

import webbrowser 

Después de eso, el módulo sólo contiene webbrowser. Entonces Python ejecuta esto:

def open_example(): 
    webbrowser.open('http://www.example.com/') 

Python crea open_example. Ahora el módulo contiene webbrowser y open_example.

Di webbrowser contenían este código:

from example_opener import open_example 

def open(url): 
    print url 

Say example_opener se importa en primer lugar. Este código se ejecuta:

import webbrowser 

webbrowser aún no ha sido importado, lo que Python ejecuta el contenido de webbrowser:

from example_opener import open_example 

example_opener ha sido importado, pero aún no se ejecuta completamente. Python no le importa. Python saca el módulo de sys.modules. En este punto, example_opener todavía está vacío. Todavía no ha definido open_example, ni ha completado la importación de webbrowser. Python no puede encontrar open_example en example_opener, por lo que falla.

¿Qué pasa si importamos open_example desde el final de webbrowser y webbrowser desde el final de example_opener? Python comenzaría mediante la ejecución de este código:

def open_example(): 
    webbrowser.open('http://www.example.com/') 

webbrowser aún no existe, pero no importa hasta open_example se llama. Ahora example_opener contiene solo open_example. A continuación, ejecuta:

import webbrowser 

que no se ha importado todavía, así que Python ejecuta webbrowser. Comienza:

def open(url): 
    print url 

Define open. A continuación, se ejecuta:

from example_opener import open_example 

example_opener está en sys.modules, por lo que utiliza eso. example_opener contiene open_example, por lo que tiene éxito. Python termina de importar webbrowser. Eso concluye importando webbrowser de example_opener. Eso es lo último en example_opener, por lo que la importación de example_opener finaliza, también.

+0

Nice breakdown. Esto es generalmente lo que tengo que hacer en django, donde a veces solo tienes que importar de forma circular. Importe en la parte inferior o dentro del alcance de la función o método. – jdi

+0

Agregó un párrafo en la parte inferior y marcó esta correcta – Hubro

+0

@Codemonkey: noté que agregó que puede evitar el uso de la sintaxis 'from ... import ...', pero ya lo tengo en mi respuesta en la parte superior: " En el caso simple, debería funcionar [...] al no usar la sintaxis 'from'. – icktoofay

12

No haga from ... import .... Simplemente haz import ... y haz referencia a sus objetos usando el nombre del módulo.

+0

No creo que se aborde un problema circular de importación sin embargo? – jdi

+4

@jdi: Lo hará. En el momento de la importación, el módulo estará vacío, pero dado que no está tratando de llegar a nada dentro de él (todavía), no importa. – icktoofay

+0

Ah, cierto. Ese es un enfoque en lugar de importar directamente en la parte inferior. – jdi

Cuestiones relacionadas