web-dev-qa-db-fra.com

Deux modules Python nécessitent le contenu de l'autre - cela peut-il fonctionner?

J'ai un module de serveur Web de bouteille avec la ligne suivante:

from foobar.formtools import auto_process_form_insert

Et le foobar.formtools le module contient cette ligne:

from foobar.webserver import redirect, redirect_back

Bien sûr, les deux entraînent les erreurs suivantes (respectivement):

ImportError: impossible d'importer le nom auto_process_form_insert
ImportError: impossible d'importer la redirection de nom

Est-ce simplement un fait qu'en Python deux modules ne peuvent pas s'importer l'un l'autre et que toutes les importations de modules doivent être de nature hiérarchique, ou suis-je en train de faire quelque chose de mal? placer toutes ces fonctions Nice dans de nouveaux modules?

53
Hubro

Modules can importez-vous cycliquement, mais il y a un hic. Dans le cas simple, cela devrait fonctionner en déplaçant les instructions import au bas du fichier ou en n'utilisant pas la syntaxe from.

Voici pourquoi cela fonctionne:

Lorsque vous importez un module, Python vérifie d'abord sys.modules. Si c'est là-dedans, il importe juste à partir de là. S'il n'est pas là, il essaie de l'importer normalement; en gros, il trouve le fichier et y exécute le contenu.

L'exécution d'un module remplit le contenu du module. Par exemple, supposons que nous ayons ce module, nommé de manière créative example_opener:

import webbrowser

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

Au début, le module est vide. Alors Python exécute:

import webbrowser

Après cela, le module ne contient que webbrowser. Alors Python exécute ceci:

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

Python crée open_example. Maintenant, le module contient webbrowser et open_example.

Supposons que webbrowser contenait ce code:

from example_opener import open_example

def open(url):
    print url

Dire example_opener est importé en premier. Ce code est exécuté:

import webbrowser

webbrowser n'a pas encore été importé, donc Python exécute le contenu de webbrowser:

from example_opener import open_example

example_openera a été importé, mais pas encore entièrement exécuté. Python ne se soucie pas. Python extrait le module de sys.modules. À ce point, example_opener est toujours vide. Il n'a pas défini open_example encore, ni même terminé l'importation webbrowser. Python ne trouve pas open_example dans example_opener, donc ça échoue.

Et si nous importions open_example à partir de la fin de webbrowser et webbrowser à partir de la fin de example_opener? Python commencerait par exécuter ce code:

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

webbrowser n'existe pas encore, mais cela n'a pas d'importance avant que open_example est appelé. Maintenant example_opener ne contient que open_example. Il exécute ensuite:

import webbrowser

Il n'a pas encore été importé, donc Python exécute webbrowser. Il démarre:

def open(url):
    print url

Il définit open. Ensuite, il exécute:

from example_opener import open_example

example_opener est dans sys.modules, donc il utilise ça. example_opener contient open_example, donc ça réussit. Python termine l'importation de webbrowser. Cela conclut l'importation de webbrowser de example_opener. C'est la dernière chose dans example_opener, donc l'importation de example_opener se termine également.

64
icktoofay

Ne faites pas from ... import .... Faites simplement import ... et référencer ses objets en utilisant le nom du module.

21
pyrospade