2016-05-17 4 views
1

Ich habe die folgende Dateistruktur, die jeweils mit höchstens einer Zeile Code (siehe unten):Ist ihm Kreis Import, wenn absoluten Import mit und __init__.py

a 
├── b 
│   ├── c.py   import a.b.d as d 
│   ├── d.py 
│   └── __init__.py from a.b.c import * 
├── __init__.py 
└── main.py   import a.b as b 

von python -m a.main läuft, bekomme ich die folgenden Fehler:

Traceback (most recent call last): 
    File "/usr/lib/python2.7/runpy.py", line 162, in _run_module_as_main 
    "__main__", fname, loader, pkg_name) 
    File "/usr/lib/python2.7/runpy.py", line 72, in _run_code 
    exec code in run_globals 
    File "/tmp/test/a/main.py", line 1, in <module> 
    import a.b as b 
    File "a/b/__init__.py", line 1, in <module> 
    from a.b.c import * 
    File "a/b/c.py", line 1, in <module> 
    import a.b.d as d 
AttributeError: 'module' object has no attribute 'b' 

Ich bin mir nicht sicher, ob dies durch zirkulären Import verursacht wird. Wenn ich import a.b.d as d zu from a.b import d ändere, gibt es keinen Fehler mehr.

+0

von 'b.py' sollten Sie in der Lage sein, nur' c' zu importieren no? –

+0

[This] (https://www.youtube.com/watch?v=0oTh1CXRaQ0) könnte sehr nützlich für die Handhabung von Importen sein, obwohl ein bisschen lang. – quapka

+0

@peter Ich habe einen anderen Beitrag, der das Erstellen und Importieren von benutzerdefinierten Modulen abdeckt. Wenn es dir hilft, bitte upvote. http://stackoverflow.com/questions/37072773/how-to-create-and-import-a-custom-module-in-python/37074372#37074372 – PyNoob

Antwort

2

Die AttributeError wird durch die as in der Importanweisung in Datei c.py verursacht.

Der ganze Prozess ist wie:

  1. main.py erstellt Modul a, um es zu sys.modules hinzugefügt und initialisiert es;
  2. main.py erstellt Modul a.b, fügte es zu sys.modules hinzu und begann, seinen Code auszuführen;
  3. b/__init__.py (a und a.b sind bereits in sys.modules) erstellt Modul a.b.c, hinzugefügt, um es zu sys.modules und beginnen, ihren Code auszuführen;
  4. b/c.py erstellt Modul a.b.d, hinzugefügt, um es zu sys.modules, ausgeführt seinen Code, hinzugefügt, um es als ein Attribut ‚d‘ des Moduls a.b, dann versucht, aber scheiterten a.b.d zu binden d zu nennen. Das Problem ist, dass das Modul a.b noch nicht initialisiert wurde, also das Attribut 'b' nicht im Modul a war.

WARUM

Um dies zu verstehen, sollten Sie wissen, dass (sowohl in Python 2 und Python 3) ein einführendes Statement macht zwei Dinge.

  1. Suchen Sie ein Modul oder Module, und initialisieren Sie es oder sie bei Bedarf;
  2. Definieren Sie einen Namen im lokalen Namespace und binden Sie ihn an ein bestimmtes Modul.

Modul findet

Erstere bezeichnet man die __import__ Haken, die das Modul lädt und initialisiert sie. In Python 2 ist der Hook standardmäßig imputil.ImportManager._import_hook und es funktioniert so.

  1. Überprüfen, ob sich das Modul in sys.modules befindet;
  2. Wenn nicht, finden Sie das Modul und erhalten Sie seinen Code;
  3. Erstellen Sie das Modul und fügen Sie es zu sys.modules;
  4. Den Code im Namensraum des Moduls ausführen;
  5. Geben Sie das Modul zurück.

Wenn die Aussage wie import a.b.c ist, wobei der Modul Findungsprozess rekursiv Modul findet a, a.b, a.b.c, und behält sie in sys.modules. Wenn das Modul a.b zurückgegeben wird, wird es als Attribut 'b' des Moduls a festgelegt. Schließlich gibt der Modulsuchprozess das oberste Modul a zurück.

Wenn die Aussage wie from a.b import c,d ist, ist das Ergebnis ein wenig anders. In diesem Fall wird das untere Modul (d. H. Das Modul a.b) zurückgegeben.

Namen Binding

Wenn Sie eine import [module] Anweisung verwenden, wird der Name des Top-Modul auf den Rückgabewert gebunden sein (das ist die Top-Modul ist). Wenn Sie eine import [module] as [name] -Anweisung verwenden, wird [name] an das untere Modul gebunden (durch Zugriff auf die Attribute des obersten Moduls).

Wenn Sie eine from [module] import [identifier] verwenden, dann wird der Name des unteren Moduls an den Rückgabewert gebunden (was in from import Anweisung das untere Modul ist).

Example 
import a.b.c   # a <- <module 'a'> 
import a.b.c as c  # c <- <module 'a'>.b.c 
from a.b import c  # c <- <module 'a.b'>.c 

In Ihrer Frage, die Import-Anweisung in c.py tritt auf, wenn Modul a.b Hälfte initialisiert und ist noch nicht in Modul a ‚s Attributen registriert. So import as wird ein Problem beim Binden von a.b.c an c auftreten. Da jedoch das Modul a.b bereits in sys.modules registriert ist, tritt bei Verwendung von from import kein solches Problem auf.

Verwandte Themen