Eine Datei aus einem Unterverzeichnis importieren?

455

Ich habe eine Datei namens tester.py, die sich auf befindet /project.

/projecthat ein Unterverzeichnis namens lib, mit einer Datei namens BoxTime.py:

/project/tester.py
/project/lib/BoxTime.py

Ich möchte importieren BoxTimeaus tester. Ich habe das versucht:

import lib.BoxTime

Was ergab:

Traceback (most recent call last):
  File "./tester.py", line 3, in <module>
    import lib.BoxTime
ImportError: No module named lib.BoxTime

Irgendwelche Ideen, wie man BoxTimeaus dem Unterverzeichnis importiert ?

BEARBEITEN

Das __init__.pywar das Problem, aber nicht vergessen , zu beziehen , BoxTimewie lib.BoxTime, oder -nutzung:

import lib.BoxTime as BT
...
BT.bt_function()
Adam Matan
quelle

Antworten:

536

Schauen Sie sich die Paketdokumentation (Abschnitt 6.4) hier an: http://docs.python.org/tutorial/modules.html

Kurz gesagt, Sie müssen eine leere Datei mit dem Namen einfügen

__init__.py

im Verzeichnis "lib".

Greg
quelle
59
Warum fühlt es sich hacky an ? Auf diese Weise markiert Python sichere / verfügbare Importverzeichnisse.
IAbstract
7
Es markiert nicht nur sichere / verfügbare Importverzeichnisse, sondern bietet auch die Möglichkeit, beim Importieren eines Verzeichnisnamens Initialisierungscode auszuführen.
Sadjad
32
Ja, das ist hackig und sogar schmutzig, und meiner Meinung nach sollte die Sprache nicht die Art und Weise auferlegen, wie Dateien über das Dateisystem geladen werden. In PHP haben wir das Problem gelöst, indem wir den Userland-Code mehrere Autoloading-Funktionen registrieren ließen, die aufgerufen werden, wenn ein Namespace / eine Klasse fehlt. Dann hat die Community den PSR-4-Standard erstellt und Composer implementiert ihn, und heutzutage muss sich niemand mehr darum kümmern. Und keine dummen fest codierten __init__Dateien (aber wenn Sie es wollen, registrieren Sie einfach einen Autoloading-Hook! Dies ist der Unterschied zwischen hacky und hackbar ).
Morgan Touverey Quilling
4
@ AurélienOomsimport sys, os; sys.path.insert(0, os.path.abspath('..')); from sibling_package.hacks import HackyHackHack
jbowman
4
Python ist eine unordentliche :)
Jimmy Pettersson
174
  • Erstellen Sie ein Unterverzeichnis mit dem Namen lib.
  • Erstellen Sie eine leere Datei mit dem Namen lib\__init__.py.
  • In lib\BoxTime.py, schreiben Sie eine Funktion foo()wie folgt aus :

    def foo():
        print "foo!"
    
  • libSchreiben Sie in Ihren Client-Code im obigen Verzeichnis :

    from lib import BoxTime
    BoxTime.foo()
    
  • Führen Sie Ihren Client-Code aus. Sie erhalten:

    foo!

Viel später - unter Linux würde es so aussehen:

% cd ~/tmp
% mkdir lib
% touch lib/__init__.py
% cat > lib/BoxTime.py << EOF
heredoc> def foo():
heredoc>     print "foo!"
heredoc> EOF
% tree lib
lib
├── BoxTime.py
└── __init__.py

0 directories, 2 files
% python 
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from lib import BoxTime
>>> BoxTime.foo()
foo!
hughdbrown
quelle
2
Könnten Sie einen Link zur Python-Dokumentation bereitstellen, in der dies erklärt wird? Vielen Dank!
Zenon
5
Lassen Sie uns diesen Link anklickbar machen: docs.python.org/3/tutorial/modules.html#packages
Gabriel Staples
Schöne Anleitung für die Implementierung eines Paketslib
MasterControlProgram
Bitte beachten Sie: Unterverzeichnisse dürfen keine Bindestriche oder Punkte enthalten, aber Unterstriche sind gültig. Für mich scheint das die gleichen Einschränkungen zu haben wie für andere Symbolnamen, aber ich habe es noch nicht auf Dokumentationsniveau gebracht.
Alexander Stohr
Unterstriche => python3 (zu spät zum Bearbeiten des Kommentars)
Alexander Stohr
68

Sie können versuchen, es einzufügen in sys.path:

sys.path.insert(0, './lib')
import BoxTime
Kresimir
quelle
11
Dies ist großartig, wenn Sie aus irgendeinem Grund die init .py-Datei nicht erstellen können oder wollen .
Jpihl
1
Es funktioniert, wenn Sie Python aus dem Verzeichnis "project" ausführen. Das "." wird relativ zu Ihrem aktuellen Arbeitsverzeichnis interpretiert, nicht relativ zu dem Verzeichnis, in dem sich die von Ihnen ausgeführte Datei befindet. Sag du cd /data, python ../project/tester.py. Dann wird es nicht funktionieren.
Morgenstern
2
Das hat bei mir funktioniert. Ich bevorzuge dies gegenüber einer init .py-Datei, da dies zu saubereren Importanweisungen führt.
Taylor Evanson
5
Dies funktioniert viel besser und ist die "richtige" Lösung. init .py bringt Pakete wie boto durcheinander, die ihre eigenen untergeordneten Ordner mit Modulen haben.
Dave Dopson
1
@jpihl Sie müssen (mindestens) eine Empy-Datei mit dem Namen __init__.py erstellen , um Python-Importmodule aus diesem Ordner zuzulassen. Ich habe diese Lösung ausprobiert und funktioniert einwandfrei (v2.7.6).
m3nda
31

Ich schreibe dies auf, weil jeder zu behaupten scheint, dass Sie ein libVerzeichnis erstellen müssen .

Sie müssen Ihr Unterverzeichnis nicht benennen lib. Sie können es benennen, anythingsofern Sie es eingeben __init__.py.

Sie können dies tun, indem Sie den folgenden Befehl in eine Linux-Shell eingeben:

$ touch anything/__init__.py 

Jetzt haben Sie also diese Struktur:

$ ls anything/
__init__.py
mylib.py

$ ls
main.py

Dann können Sie importieren mylibin main.pywie folgt aus :

from anything import mylib 

mylib.myfun()

Sie können auch Funktionen und Klassen wie folgt importieren:

from anything.mylib import MyClass
from anything.mylib import myfun

instance = MyClass()
result = myfun()

Auf jede variable Funktion oder Klasse, die Sie darin platzieren, __init__.pykann auch zugegriffen werden:

import anything

print(anything.myvar)

Oder so:

from anything import myvar

print(myvar)
nurettin
quelle
Meine Ordnerstruktur ist utils\__init__.pyund utils\myfile.py. (Utils enthalten beide Dateien) So versuche ich zu importieren from utils.myfile import myMethod. Aber ich verstehe ModuleNotFoundError: No module named 'utils'. Was könnte falsch sein? PS: Ich benutze Djangound versuche zu importieren, views.pydie auf der gleichen Ebene wie utilsOrdner ist
Jagruti
Es ist möglich, absolute Pfade beim Importieren von Modulen zu verwenden und Ihr Programm mitPYTHONPATH=. python path/to/program.py
nurettin
21

Enthält Ihr lib-Verzeichnis eine __init__.pyDatei?

Python verwendet, __init__.pyum festzustellen, ob ein Verzeichnis ein Modul ist.

Waten
quelle
16

Versuchen Sie es import .lib.BoxTime. Weitere Informationen zum relativen Import in PEP 328 finden Sie hier .

drrlvn
quelle
2
Ich glaube nicht, dass ich jemals diese Syntax gesehen habe. Gibt es einen starken Grund (nicht), diese Methode anzuwenden?
tgray
2
Warum war das nicht die Antwort? Klar, wenn du das ganze Paket machen willst, solltest du das machen. Aber das war nicht die ursprüngliche Frage.
Travis Griggs
Dies gibt mir: ValueError: Versucht relativen Import in Nicht-Paket
Alex
5
Dies funktioniert nur, wenn die Datei, aus der Sie importieren, selbst Teil eines Pakets ist. Wenn nicht, erhalten Sie den Fehler, auf den @Alex hingewiesen hat.
Jonathon Reinhart
8

Ich mache das, was im Grunde alle Fälle abdeckt (stellen Sie sicher, dass Sie sich __init__.pyin relativ / path / to / your / lib / folder befinden):

import sys, os
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/relative/path/to/your/lib/folder")
import someFileNameWhichIsInTheFolder
...
somefile.foo()


Beispiel:
Sie haben in Ihrem Projektordner:

/root/myproject/app.py

Sie haben in einem anderen Projektordner:

/root/anotherproject/utils.py
/root/anotherproject/__init__.py

Sie möchten die darin enthaltene /root/anotherproject/utils.pyFunktion foo verwenden und aufrufen.

Also schreibst du in app.py:

import sys, os
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/../anotherproject")
import utils

utils.foo()
Merkur
quelle
2
Wenn Sie verwenden os.path, möchten Sie wahrscheinlich os.path.join((os.path.dirname(os.path.realpath(__file__)),'..','anotherproject')das '/' in Ihrer Pfadverkettung verwenden, anstatt es fest zu codieren.
Cowbert
Warum kannst du nicht einfach auf das "../anotherproject"verzichten os.path.dirname()?
Moshe Rabaev
@ MosheRabaev - Es wird empfohlen, die Funktionen von os.path zu verwenden. Wenn Sie "../anotherproject" schreiben und den Code auf das Windows-Betriebssystem verschieben, wird der Code beschädigt! os.path utils weiß, wie man unter Berücksichtigung des Betriebssystems, auf dem der Code ausgeführt wird, den richtigen Pfad zurückgibt. Für weitere Informationen docs.python.org/2/library/os.path.html
Mercury
@MosheRabaev und wenn Sie ".." ohne das verwenden dirname(realpath(__file__)), berechnet es den Pfad relativ zu Ihrem aktuellen Arbeitsverzeichnis, wenn Sie das Skript ausführen, nicht relativ zu dem Ort, an dem sich das Skript befindet.
TJ Ellis
5

Erstellen Sie eine leere Datei __init__.pyim Unterverzeichnis / lib. Und am Anfang des Hauptcodes hinzufügen

from __future__ import absolute_import 

dann

import lib.BoxTime as BT
...
BT.bt_function()

oder besser

from lib.BoxTime import bt_function
...
bt_function()
Mik
quelle
0

Nur eine Ergänzung zu diesen Antworten.

Wenn Sie alle Dateien aus allen Unterverzeichnissen importieren möchten , können Sie diese zum Stammverzeichnis Ihrer Datei hinzufügen.

import sys, os
sys.path.extend([f'./{name}' for name in os.listdir(".") if os.path.isdir(name)])

Und dann können Sie einfach Dateien aus den Unterverzeichnissen importieren, als ob sich diese Dateien im aktuellen Verzeichnis befinden.

Arbeitsbeispiel

Wenn ich das folgende Verzeichnis mit Unterverzeichnissen in meinem Projekt habe ...

.
├── a.py
├── b.py
├── c.py
├── subdirectory_a
   ├── d.py
   └── e.py
├── subdirectory_b
   └── f.py
├── subdirectory_c
   └── g.py
└── subdirectory_d
    └── h.py

Ich kann den folgenden Code in meine a.pyDatei einfügen

import sys, os
sys.path.extend([f'./{name}' for name in os.listdir(".") if os.path.isdir(name)])

# And then you can import files just as if these files are inside the current directory

import b
import c
import d
import e
import f
import g
import h

Mit anderen Worten, dieser Code abstrahiert, aus welchem ​​Verzeichnis die Datei stammt.

Sieger
quelle
-1

/project/tester.py

/project/lib/BoxTime.py

Erstellen Sie eine leere Datei __init__.py, bis Sie die Datei erreichen

/project/lib/somefolder/BoxTime.py

#lib- braucht hat zwei Elemente eins __init__.pyund ein Verzeichnis namens somefolder #somefolderhat zwei Elemente boxtime.pyund__init__.py

Chaitanya Gk
quelle
-3

Versuche dies:

from lib import BoxTime

Orane
quelle
8
ohne jede Erklärung ist dies nicht sehr nützlich.
Jean-François Fabre