Python kann nicht aus einem anderen Ordner importiert werden

89

Ich kann Python scheinbar nicht dazu bringen, ein Modul in einen Unterordner zu importieren. Ich erhalte die Fehlermeldung, wenn ich versuche, eine Instanz der Klasse aus dem importierten Modul zu erstellen, aber der Import selbst ist erfolgreich. Hier ist meine Verzeichnisstruktur:

Server
    -server.py
    -Models
        --user.py

Hier ist der Inhalt von server.py:

from sys import path
from os import getcwd
path.append(getcwd() + "\\models") #Yes, i'm on windows
print path
import user

u=user.User() #error on this line

Und user.py:

class User(Entity):
    using_options(tablename='users')

    username = Field(String(15))
    password = Field(String(64))
    email    = Field(String(50))
    status   = Field(Integer)
    created  = Field(DateTime)

Der Fehler lautet: AttributeError: Das Objekt 'module' hat kein Attribut 'User'.

Ryeguy
quelle
1
Können Sie die Fehlermeldung einfügen?
Harley Holcombe
Wenn von user.py, möchte ich server.py importieren. Was mache ich?
Chandra Kanth

Antworten:

138

Ich glaube, Sie müssen eine Datei erstellen, die im Modellverzeichnis aufgerufen wird, __init__.pydamit Python sie als Modul behandelt.

Dann können Sie tun:

from Models.user import User

Sie können Code in den Code aufnehmen __init__.py(z. B. Initialisierungscode, den einige verschiedene Klassen benötigen) oder leer lassen. Aber es muss da sein.

Dana
quelle
2
Danke, ich hatte noch nie von Paketen gehört.
Ryeguy
1
Tatsächlich behandelt Python beim Importieren blah.py und und blah / __ init__.py genau gleich.
pi.
2
Das war nicht offensichtlich ... Und ich sage mir: RTFM FMF
Alexander.Iljushkin
1
Beachten Sie, dass dies nicht funktioniert, wenn Sie server.py in einem anderen Verzeichnis ausführen.
Kchoi
1
Was ist, wenn sich server.py in einem anderen Ordner befindet?
Mandroid
23

Sie müssen erstellen __init__.pyauf derModels Unterordner . Die Datei ist möglicherweise leer. Es definiert ein Paket.

Dann können Sie tun:

from Models.user import User

Lesen Sie alles über es in Python - Tutorial, hier .

Es gibt auch einen guten Artikel über Dateiorganisation von Python Projekten hier .

nosklo
quelle
Was ist, wenn die Datei NICHT leer ist?
Darkgaze
12

Benutzer importieren

u = user.User () #error in dieser Zeile

Aufgrund des oben erwähnten Mangels an __init__ würden Sie einen ImportError erwarten, der das Problem klarer macht.

Sie erhalten keine, da 'user' auch ein in der Standardbibliothek vorhandenes Modul ist. Ihre import-Anweisung greift nach dieser und versucht, die darin enthaltene User-Klasse zu finden. das gibt es nicht und erst dann bekommst du den fehler.

Im Allgemeinen ist es eine gute Idee, Ihren Import absolut zu machen:

import Server.Models.user

um diese Art von Mehrdeutigkeit zu vermeiden. In Python 2.7 sieht 'Benutzer importieren' in der Tat überhaupt nicht relativ zum aktuellen Modul aus.

Wenn Sie wirklich relative Importe wünschen, können Sie diese explizit in Python 2.5 und höher verwenden, indem Sie die etwas hässliche Syntax verwenden:

from .user import User
Bobince
quelle
9

Der richtige Weg, ein Modul in einem übergeordneten Ordner zu importieren, wenn Sie keine Standardpaketstruktur haben, ist:

import os, sys
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(CURRENT_DIR))

(Sie können die letzten beiden Zeilen zusammenführen, aber dieser Weg ist leichter zu verstehen).

Diese Lösung ist plattformübergreifend und allgemein genug, um unter anderen Umständen nicht geändert werden zu müssen.

Glarrain
quelle
7

Sie vermissen __init__.py. Aus dem Python-Tutorial:

Die Dateien __init__.py sind erforderlich, damit Python die Verzeichnisse als Pakete enthaltend behandelt. Auf diese Weise wird verhindert, dass Verzeichnisse mit einem allgemeinen Namen, z. B. eine Zeichenfolge, unbeabsichtigt gültige Module verbergen, die später im Modul-Suchpfad auftreten. Im einfachsten Fall kann __init__.py nur eine leere Datei sein, aber auch Initialisierungscode für das Paket ausführen oder die später beschriebene Variable __all__ setzen.

Fügen Sie eine leere Datei mit dem Namen __init__.py in Ihr Models-Verzeichnis ein, und alle sollten golden sein.

Harper Shelby
quelle
1

Wie schreibt man den Parameter os.path.dirname.... Befehl aus?

import os, sys
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(CURRENT_DIR))
user3440815
quelle
0

Meine bevorzugte Methode ist es, __init__.py in jedem Verzeichnis zu haben, das Module enthält, die von anderen Modulen verwendet werden, und im Einstiegspunkt sys.path wie folgt zu überschreiben:

def get_path(ss):
  return os.path.join(os.path.dirname(__file__), ss)
sys.path += [
  get_path('Server'), 
  get_path('Models')
]

Dadurch werden die Dateien in den angegebenen Verzeichnissen für den Import sichtbar, und ich kann Benutzer aus Server.py importieren.

kchoi
quelle
0

Nachdem ich die Antworten dieser Mitwirkenden oben durchgesehen hatte - Zorglub29, Tom, Mark, Aaron McMillin, Lucasamaral, Joey Zhao, Kjeld Flarup, Procyclinsur, martin.zaenker, tooty44 und das Debuggen des Problems, mit dem ich konfrontiert war, fand ich einen anderen Anwendungsfall heraus zu dem ich mit diesem Problem konfrontiert war. Daher füge ich meine Beobachtungen unten als Referenz hinzu.

In meinem Code hatte ich einen zyklischen Import von Klassen. Beispielsweise:

src
 |-- utilities.py (has Utilities class that uses Event class)  
 |-- consume_utilities.py (has Event class that uses Utilities class)
 |-- tests
      |-- test_consume_utilities.py (executes test cases that involves Event class)

Beim Versuch, python -m pytest tests / test_utilities.py zum Ausführen von in test_utilities.py geschriebenen UTs auszuführen, wurde folgende Fehlermeldung angezeigt.

ImportError while importing test module '/Users/.../src/tests/test_utilities.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/test_utilities.py:1: in <module>
    from utilities import Utilities
...
...
E   ImportError: cannot import name 'Utilities'

Die Art und Weise, wie ich den Fehler behoben habe, bestand darin, meinen Code neu zu faktorisieren, um die Funktionalität in der zyklischen Importklasse zu verschieben, damit ich den zyklischen Import von Klassen entfernen konnte.

Hinweis: Ich habe eine __init__.pyDatei in meinem Ordner ' src ' sowie in meinem Ordner ' tests ' und konnte den ' ImportError ' trotzdem entfernen , indem ich den Code neu faktorisierte .

Der folgende Stackoverflow-Link bietet viel mehr Details zur zirkulären Abhängigkeit in Python .

shekharlondhe
quelle