12
votes

Python: Pourquoi un module importé ne peut-il pas référer un autre module importé?

main.py: xxx

subone.py: xxx

subtwo.py: xxx

exécuté python main.py jette un nomError: nom "subone" n'est pas défini . Je m'attendais à imprimer «ABC».

refactorise son utilisation à partir de Importer et les classes n'aident pas:

main.py: xxx

subone.py: xxx < p> subtwo.py: xxx

mais il va imprimer 'de main.py: def'. (Cela fonctionne lorsque vous utilisez importer aussi.)

Pourquoi ça marche de cette façon? Il semble que, une fois subone est importé, il doit être disponible pour subtwo .

est-ce parce que c'est une mauvaise programmation d'avoir des modules importés dépendent l'un de l'autre Sans passer par leur module «parent»? Y a-t-il un autre moyen standard de faire cela?

Mise à jour:

Je comprends maintenant que le premier exemple ne fonctionnera pas car la ligne impression subone.a ne reconnaît pas le nom subone , ce n'est pas dans subtwo 'S Espace de noms (même s'il est dans Main.py 's), et il est appelé à partir de l'intérieur du module subtwo . Cela peut être corrigé en utilisant importer subone en haut de subtwo.py - il ne rechargera pas le module mais l'ajoutera à subtwo 's Espace de noms SO SUBTWO peut l'utiliser.

Mais qu'en est-il de ce sujet:

xxx

subone.py: xxx

subtwo.py: xxx

Je pense que depuis wrap et nugget sont tous deux chargés directement dans Main 'S Espace de noms, qu'ils utiliseraient Main S et être capables de se référencer, mais il jette un nomError: nom' nugget 'n'est pas défini . Est-ce parce que wrap est évalué / vérifié à partir de dans SUBTWO SUBTWO avant d'être chargé dans Main S ?


2 commentaires

Votre encapsulation semble vraiment cassée ...


Vous devez rechercher le scopage lexical. L'idée de base est que le code a accès à ce qu'il peut «voir» dans le code source. Que se passe-t-il au moment de l'exécution n'a rien à voir avec ça.


5 Réponses :


2
votes

Le Subtwo Espace de noms sera totalement vide que si vous importez subone dans celui-ci.

En ce qui concerne les pratiques de programmation, subone et subtwo peut dépendre de l'autre si vous le souhaitez, il vous suffit de les lier explicitement (avec un importer < / code>)


3 commentaires

D'accord, mais pourquoi ne fonctionne-t-il pas même lors de l'utilisation de - importation, qui charge tout dans l'espace de noms de l'établissement principal?


Peu importe, lorsque subtwo est exécuté (lorsque le document Importez 's), rien n'est dans SON Espace de noms.


Cela pourrait aider à se rappeler que importer dans python n'est pas comme inclure dans d'autres langues.



3
votes

Pouvez-vous expliquer pourquoi vous avez envie de subone doit être disponible pour subtwo, lorsque subone a été importé par principal? Comme c'est le cas, subtwo.py peut être compilé sans savoir ce que Main.py a importé.

Également, si un deuxième programme importe SubTwo.py, devrait-il subverser la connaissance de subone dépendent de laquelle de deux programmes principaux importateurs de subtwo? Cela réduirait la réutilisabilité de subtwo.

On dirait que vous envisagez de penser à la compilation en tant que processus avec un ordre défini, accumulant des informations sur l'état: Compiler Main.py, au cours de laquelle nous compilons / importées subone.py, accumulant des informations de celui-ci, puis nous compilons / Importer subtwo.py, en utilisant les informations que nous avons déjà accumulées.

Au lieu de cela, la compilation de chaque module est indépendante des autres, à moins que des dépendances ne soient déclarées. Cela facilite beaucoup la réutilisation et maintenir le code: il y a moins de dépendances cachées.

est-ce parce que c'est une mauvaise programmation de avoir des modules importés dépendent de chaque autre sans passer à travers leur Module 'Parent'?

Pas aussi telle ... C'est juste une mauvaise programmation pour que le module 2 dépendent du module 1 sans dire que , c'est-à-dire, sans module 2 déclarant "je dépends du module 1".


4 commentaires

Ah, je vois. La façon dont vous décrivez cela aide. Je pense que j'ai été habitué à de PHP Inclure et nécessite des instructions , qui incorporent directement le code. Au lieu de cela, les modules sont des objets qui doivent être appelés.


@WILLELL: Je n'ai jamais utilisé php, mais C est similaire avec le préprocesseur #include juste coller tout le fichier là-bas. Quoi qu'il en soit, une sorte de dépendance implicite comme celle-là ne semble tout simplement pas intelligente quelle que soit la langue.


@willell, cela a du sens ... la façon dont vous y envisagez correspond à la manière dont les mécanismes PHP et C incluent. Cependant, vous pouvez voir comment cela conduit à des dépendances difficiles à tracer ... afin de savoir quel fichier b dépend de, vous devez regarder tous les endroits où le fichier B est inclus. Il y a donc une différence fondamentale entre "y compris un fichier" et "importer un module". Le premier est davantage une insertion simple et littérale d'une chaîne de texte, inconsciente des conséquences sémantiques. Ce dernier est plus d'une liaison conceptuelle d'un composant de programme à un autre.


Ouais, je gocha. Ce que vous appelez la liaison conceptuelle, c'est une grande partie de la raison pour laquelle j'utilise Python de toute façon. La seule chose à laquelle je suis toujours confondue sur: si à partir de l'importation charge tous les objets au niveau du module dans l'espace de noms actuel, pourquoi les objets ne peuvent-ils pas se référer mutuellement? Est-ce parce que ces objets sont évalués dans leurs modules respectifs avant qu'ils ne soient chargés dans le module actuel?



6
votes

Si vous avez modifié votre subtwo.py de cette façon, il fonctionnera xxx

lorsque vous faites subonter.a dans subtwo.py, vous essayez d'accéder à l'espace de noms subone dans subtwo.py et dans l'espace de noms "subone", il devrait y avoir un attribut "A".

Lorsque vous le faites - importer subone dans subtwo.py, alors subone est ajouté à l'espace de noms et à l'espace de noms subomonal a attributé A. alors subone.Une fonctionnera.

Je suggérerais également que vous jouiez avec DIR () pour voir comment les espaces de noms sont ajoutés.

dans subtwo.py, vous pouvez faire ce qui suit : xxx

de la même manière, essayez d'ajouter "impression Dir ()" avant et après vos relevés d'importation et que l'idée devrait être claire pour vous.

"Importer x" ajoute 'x' aux modules actuels Espace de noms alors que "de x importation *" sera Ajoutez tous les attributs de niveau de module directement dans l'espace de noms de module actuel

donc dans votre premier exemple ci-dessus de MAIN.PY, subone.py et subtwo.py, l'espace de noms dans Main.py contiendra "subone" et "subtwo" pendant que subtwo.py aura Un espace de nom vide et ne peut pas accéder à subone.a.

[EDIT: quelques explications supplémentaires] Considérons les fichiers suivants: main.py xxx

subone.py xxx

subtwo.py xxx

et la sortie d'exécuter Main.py: xxx

certaines observations

  1. Vous remarquerez que l'importation d'un module subtwo.py, l'instruction d'impression est exécutée immédiatement.
  2. Alors, lorsque subone et subtwo sont importés dans Main.py, l'espace de noms de Main.py est augmenté.
  3. Cela ne signifie pas que l'espace de noms de subtwo sera augmenté. donc "A" est disponible uniquement dans Main.py Via Subone.A
  4. Lorsque nous importatent subone dans subtwo.py, l'espace de noms de Subtwo est augmenté avec subone et attribute A de sous-sompe de module est disponible dans SubTow.py via Subone.a

7 commentaires

C'est très utile. Dir () fait clairement clairement les choses pour moi. Ma seule question (comme je l'ai commentée ci-dessous) est que si "à partir de x importer *" ajoute tous les attributs de niveau de module directement dans l'espace de noms actuel, pourquoi ces attributs ne peuvent-ils pas se rencontrer?


Cette importation ne modifie pas la portée des attributs, il copie simplement leur définition à la portée locale.


@willell: Ignacio Vazquez-Abrams est correct. J'aurais dû être plus clair. Ce n'est pas la même chose que la copie du code que cela se produise en cas de #include dans "C". Les modules importés sont déjà chargés et évalués. Si vous aviez une déclaration d'impression dans un module importé, il aurait déjà été évalué.


@Ignacio: Vous dites que chaque attribut a son propre espace de noms, hérité du module it provenait?


@pyfunc: gotcha. Donc, dans mon troisième exemple dans ma question mise à jour, wrap et nugget sont évalués (et soulevez donc la nomEError) avant que leurs définitions ne soient chargées dans principal 's Espace de noms?


Chaque attribut a sa propre portée, que la référence transporte avec elle.


@Ignacio Vazquez-Abrams: @willell: +1 qui explique tout cela.



0
votes

En ce qui concerne votre deuxième exemple, "Main.py" connaît environ Nugget mais "subtwo.py" ne pas.

Je pense que cela aiderait à en penser de cette façon. Chaque module (fichier) doit fonctionner comme si seuls les seuls autres modules existants sont ceux qu'il importait. Dans ce cas "subtwo.py" ne pourra pas fonctionner en soi, car il n'a pas importé nugget . Essentiellement "subtwo.py" ne sait pas ce que "Main.py" sait. Cela ne devrait pas, parce que cela pourrait être appelé de n'importe qui, et il ne peut pas compter sur quelqu'un d'autre importer les choses qu'elle a besoin.


0 commentaires

0
votes

En effet, les modules importés ont ses propres espaces de noms distincts. Ce que vous avez écrit, c'est beaucoup comme: xxx

Les modules ont leurs espaces de noms localement, et lorsque vous utilisez à partir de subone import * vous importez l'espace de noms uniquement sur Main.py Espace de noms qui ne peut pas être accédé par Subtwo .

Néanmoins - ce que vous essayez de faire est une très mauvaise pratique. Évitez d'utiliser des variables globales et importer * , juste parce que vous aurez de plus en plus confus comme maintenant.


plus sur ce: https://docs.python.org/3/reference/import.html

https://bytebaker.com/2008/07 / 30 / Python-Namespaces /

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

et peut-être: http://sebastianraschka.com/articles/2014_python_scope_and_namespaces.html


0 commentaires