2016-01-25 10 views
9

Ich versuche ein Python-Skript zu erstellen, das in mehrere Dateien aufgeteilt ist, damit ich es einfacher verwalten kann, anstatt ein sehr langes Einzeldatei-Skript zu erstellen . HierPython-Importfehler: 'Modul' -Objekt hat kein Attribut 'x'

ist die Verzeichnisstruktur:

wmlxgettext.py 
<pywmlx> 
    |- __init__.py 
    |- (some other .py files) 
    |- <state> 
     |- __init__.py 
     |- state.py 
     |- machine.py 
     |- lua_idle.py 

wenn ich erreichen das Hauptverzeichnis meines Projekts (wo das wmlxgettext.py Skript gespeichert ist) und wenn ich versuche, „import pywmlx“ Ich habe einen Importfehler (error Attribut: ‚Modul‘ Objekt hat kein Attribut ‚Zustand‘)

Dies ist die komplette Fehlermeldung:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/home/user/programmi/my/python/wmlxgettext/true/pywmlx/__init__.py", line 9, in <module> 
    import pywmlx.state as statemachine 
    File "/home/user/programmi/my/python/wmlxgettext/true/pywmlx/state/__init__.py", line 1, in <module> 
    from pywmlx.state.machine import setup 
    File "/home/user/programmi/my/python/wmlxgettext/true/pywmlx/state/machine.py", line 2, in <module> 
    from pywmlx.state.lua_idle import setup_luastates 
    File "/home/user/programmi/my/python/wmlxgettext/true/pywmlx/state/lua_idle.py", line 3, in <module> 
    import pywmlx.state.machine as statemachine 
AttributeError: 'module' object has no attribute 'state' 

Da ich in der „Projekt-Hauptverzeichnis“ pywmlx bin sollte auf PYTHONPATH (tatsächlich habe ich keine Probleme, wenn ich versuchte, pywmlx/something.py zu importieren)

Ich bin nicht in der Lage zu berechnen, wo ist mein Fehler und wie dieses Problem zu lösen. Hier

ist die pywmlx/__ init__.py Quelle:

# all following imports works well: 
from pywmlx.wmlerr import ansi_setEnabled 
from pywmlx.wmlerr import wmlerr 
from pywmlx.wmlerr import wmlwarn 
from pywmlx.postring import PoCommentedString 
from pywmlx.postring import WmlNodeSentence 
from pywmlx.postring import WmlNode 

# this is the import that does not work: 
import pywmlx.state as statemachine 

Hier ist die pywmlx/Zustand/__ init__.py Quelle:

from pywmlx.state.machine import setup 
from pywmlx.state.machine import run 

Aber ich denke, dass die reale Das Problem ist etwas versteckt in den "Importen", die von einem (oder allen) Python-Modulen verwendet werden, die im Verzeichnis pywmlx/state gespeichert sind. Hier

ist die pywmlx/Bundesland/machine.py Quelle:

# State is a "virtual" class 
from pywmlx.state.state import State 
from pywmlx.state.lua_idle import setup_luastates 
import pywmlx.nodemanip as nodemanip 

def addstate(self, name, value): 
    # code is not important for this question 
    pass 

def setup(): 
    setup_luastates() 

def run(self, *, filebuf, fileref, fileno, startstate, waitwml=True): 
    # to do 
    pass 

Schließlich ist hier die pywmlx/Bundesland/lua_idle.py Quelle:

import re 
import pywmlx.state.machine as statemachine 
# State is a "virtual" class 
from pywmlx.state.state import State 

# every state is a subclass of State 
# all proprieties were defined originally on the base State class: 
    # self.regex and self.iffail were "None" 
    # the body of "run" function was only "pass" 
class LuaIdleState (State): 
    def __init__(self): 
     self.regex = re.compile(r'--.*?\s*#textdomain\s+(\S+)', re.I) 
     self.iffail = 'lua_checkpo' 

    def run(xline, match): 
     statemachine._currentdomain = match.group(1) 
     xline = None 
     return (xline, 'lua_idle') 


def setup_luastates(): 
    statemachine.addstate('lua_idle', LuaIdleState) 

Sorry, wenn ich habe so viel Code und so viele Dateien gepostet ... aber ich fürchte, dass die Dateien im Verzeichnis mehr als ein einziges Importproblem verbergen, also habe ich sie alle veröffentlicht, in der Hoffnung, dass ich das Problem erklären und Verwirrung vermeiden könnte.

Ich denke, dass ich etwas darüber vermisse, wie Import in Python funktioniert, also hoffe ich, dass diese Frage auch für andere Programmierer nützlich sein kann, weil ich denke, dass ich nicht die einzige bin, die die offizielle Dokumentation sehr schwierig zu verstehen fand einführen. Fertig


Suchen:

Not Useful: Ich bin schon explizit mit Import x.y.z alle Male, die ich brauche etwas

Not Useful importieren: Auch wenn die Frage nach dem Importfehler fragt, scheint es nicht sinnvoll, aus dem gleichen Grund wie (1)

Not Useful: Soweit ich weiß, pywmlx sollte in PYTHONPATH seit "aktuellen Arbeitsverzeichnis" in meinen Tests befindet sich das Verzeichnis, das das Haupt-Python-Skript und pywmlx Verzeichnis befindet. Korrigieren Sie mich, wenn ich falsch liege

+0

Können Sie versuchen, den problematischen Import in 'aus zu ändern. Staat als Staatsmaschine importieren? –

+0

haben Sie zuerst mit leeren __init__ Dateien versucht? Wenn dies funktioniert, versuchen Sie nicht, Aliasing (Import as) zu verwenden, da dies zu Namespace-Konflikten führen kann. Ich denke, Sie haben zirkuläre Importe mit vermasseltem Namensraum. Versuchen Sie immer den vollen Namen zu verwenden (nur Import schreiben, nein von Importen). – Serbitar

+0

@Serbitar: Ich möchte Ihren Kommentar "abstimmen", weil Ihr Vorschlag sehr gut funktioniert. Das Ersetzen von __import pywmlx.state.machine als statemachine__ mit nur __import pywmlx.state.machine__ auf __pywmlx/state/lua_idle.py__ funktioniert sehr gut (wahrscheinlich verursacht das Aliasing von pywmlx.state.machine als Statemachine einen Konflikt mit dem von __pywmlx/\ verwendeten Aliasing. _ \ _ init \ _ \ _. py__ wo __pywmlx.state__ als __statemachine__ aliasiert ist Ich weiß nicht, wie man eine positive Bewertung für deinen Kommentar markiert:/Ich würde es gerne tun – Nobun

Antwort

9

Python mehrere Dinge tut, wenn Pakete importieren:

  • ein Objekt in sys.modules für das Paket erstellen, mit dem Namen als Schlüssel: 'pywmlx', 'pywmlx.state', 'pywmlx.state.machine' usw.
  • Führen Sie den für dieses Modul geladenen Bytecode aus. Dies kann mehr Module erstellen.
  • Sobald ein Modul vollständig geladen ist und sich in einem anderen Paket befindet, legen Sie das Modul als Attribut des übergeordneten Modulobjekts fest. Somit wird das sys.modules['pywmlx.state'] Modul als das state Attribut auf dem Modulobjekt festgelegt.

Diesen letzter Schritt Ort noch in Ihrem Beispiel nicht getroffen hat, aber die folgende Zeile funktioniert nur, wenn sie gesetzt worden ist:

import pywmlx.state.machine as statemachine 

weil diese nach oben sieht sowohl state und machine als erstes Attribut. Verwenden Sie diese Syntax statt:

from pywmlx.state import machine as statemachine 

Alternativ können Sie nur

import pywmlx.state.machine 

und ersetzen statemachine. überall sonst mit pywmlx.state.machine.. Dies funktioniert, weil all das, was Ihrem Namespace hinzugefügt wird, ein Verweis auf das sys.modules['pywmlx']-Modulobjekt ist und die Attributreferenzen nicht aufgelöst werden müssen, bis Sie diesen Verweis in den Funktionen und Methoden verwenden.

+0

Vielen Dank für Ihre Antwort.Ich bin mir nicht sicher, ob ich all deine Erklärungen verstanden habe, aber ich schätze die großartige Arbeit, die du geleistet hast, als du versucht hast, solch eine komplexe Sache auf vereinfachte Weise zu erklären (tiefgreifend zu verstehen, wie Import funktioniert). Ich habe deine Lösung nicht versucht (was wahrscheinlich gut funktioniert), da das Entfernen von Alias ​​aus dem __import__, das auf __lua_idle.py__ verwendet wird, auch funktioniert und es ist eine Lösung, die besser mit dem von pywmlx verwendeten Namespace übereinstimmt. – Nobun

+0

@Nobun: sicher, das funktioniert auch; Ich habe diese Alternative zu der Antwort hinzugefügt. –

+0

'Dieser letzte Schritt hat in deinem Beispiel noch nicht stattgefunden. Warum denkst du das? – ecoe

2

Sie haben einen kreisförmigen Import in Ihrem Framework. Zirkuläre Importe funktionieren nicht gut mit Aliasen. Wenn ein Modul mit einem Alias ​​importiert wird und dann während des zirkulären Imports erneut ohne Alias ​​importiert wird, beschwert sich Python. Die Lösung besteht darin, keine Aliase (die Syntax "Importmodul als") zu verwenden, sondern immer die vollständige Anweisung "Importmodul" zu verwenden.

Verwandte Themen