2016-01-25 26 views
9

Sto provando a fare uno script python che è diviso in più file, quindi posso mantenerlo più facilmente invece di fare uno script di file singolo molto lungo .Errore di importazione Python: l'oggetto 'module' non ha attributo 'x'

Ecco la struttura di directory:

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

se raggiungere la directory principale del mio progetto (in cui è archiviato lo script wmlxgettext.py) e se provo a "importare pywmlx" ho un errore di importazione (attributo errore: 'modulo' oggetto non ha attributo 'stato')

Ecco il messaggio di errore completo:

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' 

Dato che io sono nel pywmlx "progetto di directory principale" dovrebbe essere su PYTHONPATH (infatti non ho problemi quando ho provato a importare pywmlx/something.py)

Non riesco a capire dove sia il mio errore e come risolvere questo problema.

Ecco la pywmlx/__ init__.py fonte:

# 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 

Ecco la pywmlx/stato/__ init__.py fonte:

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

Ma penso che il vero il problema è in qualche modo nascosto nelle "importazioni" usate da uno (o tutti) i moduli python memorizzati nella directory pywmlx/state.

Ecco la pywmlx/stato/machine.py fonte:

# 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 

Infine ecco il pywmlx/stato/lua_idle.py fonte:

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) 

Scusate se postato tanto codice e tanti file ... ma temo che i file, nella directory, nascondano più di un singolo problema di importazione, quindi li ho pubblicati tutti, sperando di poter spiegare il problema evitando la confusione.

Penso che mi manchi qualcosa su come l'importazione funziona in python, quindi spero che questa domanda possa essere utile anche ad altri programmatori, perché penso di non essere l'unica a trovare la documentazione ufficiale molto difficile da capire quando spiegano importare.


ricerche fatte:

Not Useful: Sono già in modo esplicito utilizzando l'importazione x.y.z tutte le volte che ho bisogno di importare qualcosa

Not Useful: Anche se la domanda chiede di errori di importazione, non sembra utile per lo stesso motivo (1)

Not Useful: Per quanto ne so, pywmlx dovrebbe trovarsi in PYTHONPATH poiché "directory di lavoro corrente" sui miei test è la directory che contiene lo script python principale e la directory pywmlx. Correggetemi se sbaglio

+0

Puoi provare a cambiare l'importazione problematica in "from". stato di importazione come statemachine'? –

+0

hai provato prima con i file __init__ vuoti? Se funziona, prova a non utilizzare l'aliasing (importa come) poiché questo può portare a conflitti nello spazio dei nomi. Penso che tu stia avendo importazioni circolari con namespace incasinato. Cerca di utilizzare sempre il nome completo (solo importa import ..., no da importazioni). – Serbitar

+0

@Serbitar: mi piacerebbe "votare" il tuo commento, perché il tuo suggerimento funziona molto bene. Sostituire __import pywmlx.state.machine come statemachine__ con solo __import pywmlx.state.machine__ su __pywmlx/state/lua_idle.py__ funziona molto bene (probabilmente, aliasing pywmlx.state.machine come statemachine crea un conflitto con l'aliasing usato da __pywmlx/\ _ \ _ init \ _ \ _. py__ dove __pywmlx.state__ è aliasato come __statemachine__ anche io. Non so come segnare un voto positivo sul tuo commento:/Mi piacerebbe farlo – Nobun

risposta

9

Python fa diverse cose durante l'importazione di pacchetti:

  • creare un oggetto in sys.modules per il pacchetto, con il nome come chiave: 'pywmlx', 'pywmlx.state', 'pywmlx.state.machine', ecc
  • Esegui il bytecode caricato per quel modulo; questo potrebbe creare più moduli.
  • Una volta che il modulo è completamente caricato e si trova all'interno di un altro pacchetto, impostare il modulo come attributo dell'oggetto modulo genitore. Pertanto il modulo sys.modules['pywmlx.state'] è impostato come attributo state sull'oggetto modulo sys.modules['pywmlx'].

Questo ultimo passaggio non ha ancora avuto luogo nel tuo esempio, ma la riga seguente funziona solo quando è stato impostato:

import pywmlx.state.machine as statemachine 

perché questo guarda in alto sia state e machine come attributi prima. Utilizzare questa sintassi invece:

from pywmlx.state import machine as statemachine 

In alternativa, basta usare

import pywmlx.state.machine 

e sostituire statemachine. ovunque con pywmlx.state.machine.. Funziona perché tutto ciò che viene aggiunto al tuo spazio dei nomi è un riferimento all'oggetto modulo sys.modules['pywmlx'] e i riferimenti agli attributi non dovranno essere risolti finché non utilizzerai tale riferimento nelle funzioni e nei metodi.

+0

Grazie mille per la risposta.Non sono sicuro di aver capito tutta la tua spiegazione, ma ho apprezzato il grande lavoro che hai svolto quando hai cercato di spiegare una cosa così complessa (comprendendo profondamente come funziona l'importazione) in modo semplificato. Non ho provato la tua soluzione (che probabilmente funzionerà bene) poiché la rimozione dell'alias dal __import__ utilizzato su __lua_idle.py__ funziona pure ed è una soluzione che si adatta meglio a ciò che sto cercando di gestire con gli spazi dei nomi usati da pywmlx :) – Nobun

+0

@Nobun: certo, questo funziona anche; Ho aggiunto quell'alternativa alla risposta. –

+0

'L'ultimo passaggio non è ancora avvenuto nel tuo esempio 'perché pensi? – ecoe

2

Si sta eseguendo un'importazione circolare nel framework. Le importazioni circolari non funzionano bene con gli alias. Quando si importa un modulo con un alias e quindi, durante l'importazione circolare, importandolo di nuovo senza un alias, Python si lamenta. La soluzione è di non usare alias (la sintassi "import module as") ma di usare sempre l'istruzione completa "import module".

Problemi correlati