2015-09-24 11 views
6

Was ist der richtige Weg in Python ein Modul aus einem Verzeichnis eine Ebene höher zu importieren? Das Verzeichnis ist ein Python-Paket mit all diesen Modulen und ich habe ein Unterverzeichnis mit Code, der diese Module benötigt.Importieren eines Moduls aus einem Verzeichnis (Paket) eine Ebene höher

Das folgende funktioniert gut, aber das ist nur ein Hack. Ich hätte gerne einen empfohlenen/pythonischen Weg.

import sys 
sys.path.append("../") 
from fruit import Fruit 
print("OK") 

Die Verzeichnisstruktur:

pkg1 
    __init__.py 
    fruit.py 
    +sub_pkg 
     __init__.py 
     recipe.py 

Inhalt fruit.py

class Fruit: 
    def get_name(self): 
     print("Fruit name") 

Inhalt sub_pkg/recipe.py .. nur eine einzige Zeile importieren:

from fruit import Fruit 

Als ich Lauf :

python recipe.py 

gibt es den folgenden Fehler.

Traceback (most recent call last): 
    File "recipe.py", line 2, in <module> 
    from fruit import Fruit 
ImportError: No module named fruit 

ich auch versucht: from pkg1.fruit import Fruit, funktioniert nicht. Auch andere ähnliche Fragen .. python -m recipe.py oder python -m sub_pkg/recipe.py hat nicht funktioniert.

+0

Was Über diese Antwort: http://stackoverflow.com/questions/72852/how-to-do-relative-imports-in-python –

+0

Was? ist der Fehler, den Sie für 'von pkg1.fruit import Fruit' bekommen? – Forge

+0

@Irit: 'ImportError: Kein Modul namens Temp.Fruit' – stackjs

Antwort

2

In Ihrer Hauptdatei recipe.pypkg1 Pfad zum PYTHONPATH

sys.path.append('/path/to/pkg1') 

hinzufügen oder einen relativen Pfad Dieser

sys.path.append('../..') 

verwenden lassen soll pkg1 von jedem, wo in Ihrem Programm zu importieren.

Es gibt immer die Möglichkeit, relative Importe zu verwenden, wie hier vorgeschlagen, finde ich mit absoluten Importen lesbarer und weniger wahrscheinlich zu Fehlern führen. In großen Projekten, in denen relative Importe verwendet werden, werden Sie ständig Pfadhierarchien berechnen, während Sie bei absoluten Importen einfach wissen, dass Sie immer auf ein Stammverzeichnis verweisen.

über relative Einfuhren aus PEP328 in Python 2.5:

Reading code which relies on relative imports is also less clear, because a reader may be confused about which module is intended to be used. Python users soon learned not to duplicate the names of standard library modules in the names of their packages’ submodules, but you can’t protect against having your submodule’s name being used for a new module added in a future version of Python.


Guido schlagen mit führenden Punkten in relativen Einfuhren mehrdeutig Einfuhren zu vermeiden, wie oben beschrieben, von PEP328 wieder:

Guido has Pronounced that relative imports will use leading dots. A single leading dot indicates a relative import, starting with the current package. Two or more leading dots give a relative import to the parent(s) of the current package, one level per dot after the first.

+0

eingerichtet PYTHONPATH funktioniert und scheint wie eine akzeptable Lösung (Hinzufügen des Pkg zum Suchpfad) basierend auf Dokumentation. Ich hatte sys.path.append bereits ausprobiert, entschied mich jedoch, diesen Weg nicht zu gehen – stackjs

2

Wenn Sie Probleme haben, können Sie auch Folgendes verwenden.

Diese Importe aus aktuellem Verzeichnis

from . import something 

diesen Import von einem Verzeichnis über

from .. import fruit 

Doc zum relativen Pfad: https://docs.python.org/2/tutorial/modules.html#intra-package-references

RELATIVE PACKAGE ISSUE Valueerror: Versuchte relativer Import in non -Paket

Für Leute, die Probleme mit dem entsprechenden Paket haben. Hier ist deine Lösung.

if __name__ == "__main__" and __package__ is None: 
    __package__ = "expected.package.name" 

Auch die Erklärung, kopiert von einem anderen python docs

When the main module is specified by its filename, then the package attribute will be set to None . To allow relative imports when the module is executed directly, boilerplate similar to the following would be needed before the first relative import statement:

if __name__ == "__main__" and __package__ is None: 
    __package__ = "expected.package.name 

Note that this boilerplate is sufficient only if the top level package is already accessible via sys.path . Additional code that manipulates sys.path would be needed in order for direct execution to work without the top level package already being importable.

Doc für die Erstellung von Paketen Ich bin nicht der Inhalt gehen einzufügen, da es ziemlich lang ist, aber Hier ist der Abschnitt über die Python-Dokumente zum Erstellen von Paketen. https://docs.python.org/2/tutorial/modules.html#packages

Eine weitere Dokumente auf PYTHONPATH https://docs.python.org/2/using/cmdline.html#envvar-PYTHONPATH

+0

Fast zur gleichen Zeit !! – avenet

+0

danke .. Wenn ich eine dieser Methoden mache, ergibt sich 'ValueError: Versuch eines relativen Imports in Nicht-Paket'. Dies ist der gleiche Fehler, den Olexander in einer anderen Frage aufgezeigt hat. Aber habe die Lösung nicht verstanden! – stackjs

+0

Sie verweisen auf das Dokument. Das ist immer vorteilhafter. – AdriVelaz

-1

Statt oberen Importe verwenden, haben einen Einstiegspunkt, den Sie von der obersten Ebene aufrufen und haben Sie Ihre Importe relativ zu diesem Einstiegspunkt in Ihrer Datei recipe.py.

Ex:

pkg1/ 
    __init__.py 
    main.py 
    fruit.py 
    +sub_pkg 
     __init__.py 
     recipe.py 

Wo main.py enthält:

#!/usr/bin/env python3 

import subpkg.recipe as recipe 
import fruit 

if __package__ is None and __name__ == "__main__": 
    __package__ = "main" 
    print() 
    # Call recipe.py or fruit.py methods from here 

Und in recipe.py:

import fruit 
# do stuff with fruit module, which is properly imported now 

ausführen zu können, rufen python3 main.py

+0

Es wäre vorteilhafter, das Paket innerhalb des Skripts zu adressieren. anstatt ein separates Laufskript zu erstellen. Dadurch wird verhindert, dass ein Skript ausgeführt wird, das in einigen Szenarien möglicherweise nicht skaliert wird. – AdriVelaz

+0

@AdriVelaz Adresse welches Paket in welcher Liste? Ich brauche Kontext – NuclearPeon

+0

'__package__ = "expected.package.name"' mit 'wenn __name__ == "__main __":' auf der Skriptebene Hier sind die auch docs. https://www.python.org/dev/peps/pep-0366/#proposed-change – AdriVelaz

Verwandte Themen