2016-01-25 37 views
9

Próbuję zrobić skrypt Pythona, który jest podzielony na wiele plików, więc mogę go łatwiej utrzymać zamiast tworzyć bardzo długi pojedynczy skrypt pliku .Błąd importu Pythona: obiekt 'module' nie ma atrybutu 'x'

Oto struktura katalogów:

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

jeśli dojdę do katalogu głównego mojego projektu (gdzie przechowywana jest wmlxgettext.py skrypt) i gdy próbuję „Importuj pywmlx” Mam błąd importu (atrybut error: „moduł” obiekt ma atrybut „państwo”)

Oto pełna komunikat o błędzie:

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' 

Ponieważ jestem w „katalog główny projekt powinien być” pywmlx na PYTHONPATH (w rzeczywistości nie mam problemów, gdy próbowałem zaimportować pywmlx/something.py)

Nie jestem w stanie określić, gdzie jest mój błąd i jak rozwiązać ten problem.

Oto pywmlx/__ init__.py źródło:

# 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 

Oto pywmlx/state/__ init__.py źródło:

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

Ale myślę, że prawdziwe problem jest nieco ukryty w "importach" używanych przez jeden (lub wszystkie) moduły python przechowywane w katalogu pywmlx/state.

Oto pywmlx/state/machine.py źródło:

# 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 

Wreszcie jest tu pywmlx/state/lua_idle.py źródło:

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) 

Przepraszam, jeśli wysłałem tyle kodu i tyle plików ... ale obawiam się, że pliki w katalogu ukrywają więcej niż jeden problem z importowaniem, więc opublikowałem je wszystkie, mając nadzieję, że uda mi się wyjaśnić problem, unikając zamieszania.

Myślę, że brakuje mi czegoś o tym, jak import działa w Pythonie, więc mam nadzieję, że to pytanie może być przydatne także dla innych programistów, ponieważ uważam, że nie jestem jedynym, który uznał oficjalną dokumentację bardzo trudną do zrozumienia, wyjaśniając import.


Wyszukiwania Sporządzono:

Not Useful: Ja już jawnie przy użyciu importu x.y.oo Wszystkie czasy muszę importować coś

Not Useful: Nawet jeśli pytanie prosi o błędach importu, to nie wydaje się użyteczne dla tego samego powodu co (1)

Not Useful: O ile wiem, pywmlx powinien znajdować się w PYTHONPATH, ponieważ "bieżący katalog roboczy" w moich testach jest katalogiem zawierającym główny skrypt python i katalog pywmlx. Popraw mnie jeśli się mylę

+0

Czy możesz spróbować zmienić problematyczny import na 'z. importować stan jako statemachine'? –

+0

Najpierw próbowałeś z pustymi plikami __init__? Jeśli to działa, spróbuj nie używać aliasingu (importuj jako), ponieważ może to prowadzić do konfliktów przestrzeni nazw. Wydaje mi się, że masz import cykliczny z pomieszaną przestrzenią nazw. Staraj się zawsze używać pełnej nazwy (tylko napisz import ..., nie z importu). – Serbitar

+0

@Serbitar: Chciałbym "zagłosować" na twój komentarz, ponieważ twoja sugestia działa bardzo dobrze. Zastępowanie __import pywmlx.state.machine jako statemachine__ tylko z __import pywmlx.state.machine__ na __pywmlx/state/lua_idle.py__ działa bardzo dobrze (prawdopodobnie aliasing pywmlx.state.machine jako statemachine powoduje konflikt z aliasingiem używanym przez __pywmlx/\ _ \ _ init \ _ \ _. py__ gdzie __pywmlx.state__ jest również aliasem jako __statemachine__ Nie wiem, jak oznaczyć pozytywny głos w twoim komentarzu:/Chciałbym to zrobić – Nobun

Odpowiedz

9

Python robi kilka rzeczy podczas importowania pakiety:

  • utworzyć obiekt w sys.modules na opakowaniu z nazwą jako klucz: 'pywmlx', 'pywmlx.state', 'pywmlx.state.machine' itp
  • Uruchom kod bajtowy załadowany dla tego modułu; to może stworzyć więcej modułów.
  • Po pełnym załadowaniu modułu i umieszczeniu go w innym pakiecie, ustaw moduł jako atrybut obiektu modułu macierzystego. Tak więc moduł sys.modules['pywmlx.state'] jest ustawiony jako atrybut state na obiekcie modułu sys.modules['pywmlx'].

To ostatni krok nie nastąpiło jeszcze w przykładzie, ale następujący wiersz działa tylko wtedy, gdy został ustawiony:

import pywmlx.state.machine as statemachine 

ponieważ patrzy się zarówno state i machine jako atrybuty pierwszy. Użyj tej składni zamiast:

from pywmlx.state import machine as statemachine 

Alternatywnie, wystarczy użyć

import pywmlx.state.machine 

i zastąpić statemachine. wszędzie z pywmlx.state.machine.. Działa to, ponieważ wszystko, co jest dodawane do obszaru nazw, jest odniesieniem do obiektu modułu sys.modules['pywmlx'], a odniesienia do atrybutów nie będą wymagały rozstrzygnięcia, dopóki nie użyjesz tego odwołania w funkcjach i metodach.

+0

Dziękuję bardzo za odpowiedź.Nie jestem pewien, czy zrozumiałem wszystkie twoje wyjaśnienia, ale doceniam wspaniałą pracę, którą wykonałeś, kiedy próbowałeś wyjaśnić tak skomplikowaną rzecz (w dużym stopniu zrozumiesz, jak działa import) w uproszczony sposób. Nie wypróbowałem twojego rozwiązania (które prawdopodobnie będzie działać dobrze), ponieważ usuwanie aliasu z __import__ używanego w __lua_idle.py__ również działa i jest to rozwiązanie, które lepiej pasuje do tego, co próbuję zarządzać z przestrzeniami nazw używanymi przez pywmlx :) – Nobun

+0

@Nobun: na pewno to też działa; Dodałem tę alternatywę do odpowiedzi. –

+0

'Ten ostatni krok jeszcze nie miał miejsca w twoim przykładzie" dlaczego tak myślisz? – ecoe

2

Masz cykliczny import w swojej strukturze. Okrężne importowanie nie działa dobrze z aliasami. Podczas importowania modułu za pomocą aliasu, a następnie podczas importu kołowego, importując go ponownie bez aliasu, narzeka Python. Rozwiązaniem jest nie używanie aliasów (składnia "importuj moduł jako"), ale zawsze używaj pełnej instrukcji "moduł importu".

Powiązane problemy