Warum python findet Modul statt Paket, wenn sie den gleichen Namen haben?

Hier ist meine Verzeichnisstruktur:

/home/dmugtasimov/tmp/name-res root tests __init__.py test_1.py __init__.py classes.py extra.py root.py 

Dateiinhalt : root / tests / _ init _.py

 import os, sys ROOT_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')) if not sys.path or ROOT_DIRECTORY not in sys.path: sys.path.insert(0, ROOT_DIRECTORY) # These imports are required for unittest to find test modules in package properly from root.tests import test_1 

Root / tests / test_1.py

 import unittest from root.classes import Class1 class Tests(unittest.TestCase): pass 

Root / _ init _.py – leer
Root / classes.py

 import os, sys ROOT_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) if not sys.path or ROOT_DIRECTORY not in sys.path: sys.path.insert(0, ROOT_DIRECTORY) print 'sys.path:', sys.path print 'BEFORE: import root.extra' import root.extra print 'AFTER: import root.extra' class Class1(object): pass class Class2(object): pass 

Root / extra.py

 class Class3(object): pass 

Root / root.py

 import os import sys ROOT_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) if not sys.path or ROOT_DIRECTORY not in sys.path: sys.path.insert(0, ROOT_DIRECTORY) from classes import Class2 

Ich bekomme folgende Ausgabe:

 $ python -m unittest tests.test_1 sys.path: ['/home/dmugtasimov/tmp/name-res', '', '/usr/local/lib/python2.7/dist-packages/tornado-2.3-py2.7.egg', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client'] BEFORE: import root.extra sys.path: ['/home/dmugtasimov/tmp/name-res', '', '/usr/local/lib/python2.7/dist-packages/tornado-2.3-py2.7.egg', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client'] BEFORE: import root.extra Traceback (most recent call last): File "/usr/lib/python2.7/runpy.py", line 162, in _run_module_as_main "__main__", fname, loader, pkg_name) File "/usr/lib/python2.7/runpy.py", line 72, in _run_code exec code in run_globals File "/usr/lib/python2.7/unittest/__main__.py", line 12, in <module> main(module=None) File "/usr/lib/python2.7/unittest/main.py", line 94, in __init__ self.parseArgs(argv) File "/usr/lib/python2.7/unittest/main.py", line 149, in parseArgs self.createTests() File "/usr/lib/python2.7/unittest/main.py", line 158, in createTests self.module) File "/usr/lib/python2.7/unittest/loader.py", line 128, in loadTestsFromNames suites = [self.loadTestsFromName(name, module) for name in names] File "/usr/lib/python2.7/unittest/loader.py", line 91, in loadTestsFromName module = __import__('.'.join(parts_copy)) File "tests/__init__.py", line 9, in <module> from root.tests import test_1 File "/home/dmugtasimov/tmp/name-res/root/tests/__init__.py", line 9, in <module> from root.tests import test_1 File "/home/dmugtasimov/tmp/name-res/root/tests/test_1.py", line 3, in <module> from root.classes import Class1 File "/home/dmugtasimov/tmp/name-res/root/classes.py", line 9, in <module> import root.extra File "/home/dmugtasimov/tmp/name-res/root/root.py", line 6, in <module> from classes import Class2 ImportError: cannot import name Class2 

Es stellt sich heraus, das Problem ist die Reihenfolge von Python-Interpreter verwendet, um für Paket oder Modul zu suchen:

 $ python -vv -m unittest tests.test_1 …skipped... import root.classes # precompiled from /home/dmugtasimov/tmp/name-res/root/classes.pyc sys.path: ['/home/dmugtasimov/tmp/name-res', '', '/usr/local/lib/python2.7/dist-packages/tornado-2.3-py2.7.egg', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client'] BEFORE: import root.extra # trying /home/dmugtasimov/tmp/name-res/root/root.so # trying /home/dmugtasimov/tmp/name-res/root/rootmodule.so # trying /home/dmugtasimov/tmp/name-res/root/root.py # /home/dmugtasimov/tmp/name-res/root/root.pyc matches /home/dmugtasimov/tmp/name-res/root/root.py …skipped... 

Nach python dokumentation http://docs.python.org/2/tutorial/modules.html#the-module-search-path : "Wenn ein Modul namens Spam importiert wird, sucht der Interpreter zunächst nach einem eingebauten Modul mit dieser Name. Wenn nicht gefunden, sucht es dann nach einer Datei namens spam.py in einer Liste von Verzeichnissen, die von der Variablen sys.path angegeben werden. "

Dies bedeutet, dass Python sollte auf sys.path Index 0 Eintrag zu sehen, erhalten Pfad '/ home / dmugtasimov / tmp / name-res' und finden Paket namens root und dann suchen Modul namens extra in diesem Paket. Aber stattdessen sucht es in / home / dmugtasimov / tmp / name-res / root / Verzeichnis für Modul-Root und versucht dann, etwas zu finden, das extra extra wird. Was passiert damit? Stimmt es nicht der offiziellen Dokumentation zu? Oder sind Regeln für die Suche von Paketen anders als für Module? Wenn ja, sind diese Regeln irgendwo in der Dokumentation abgedeckt?

AKTUALISIEREN

Ich habe es hier für eine bessere Formatierung.
Für weitere Untersuchungen:

  1. Root.pyc entfernen
  2. Umbenennen von root.py zu root2.py
  3. Führen Sie python -vv -m unittest tests.test_1
 # trying /home/dmugtasimov/tmp/name-res/root/root.so # trying /home/dmugtasimov/tmp/name-res/root/rootmodule.so # trying /home/dmugtasimov/tmp/name-res/root/root.py # trying /home/dmugtasimov/tmp/name-res/root/root.pyc # trying /home/dmugtasimov/tmp/name-res/root/extra.so # trying /home/dmugtasimov/tmp/name-res/root/extramodule.so # trying /home/dmugtasimov/tmp/name-res/root/extra.py 

Es scheint python ignorieren sys.path nur für erste 4 Versuche.

UPDATE 2

Vereinfachte Version:

 /home/dmugtasimov/tmp/name-res3/xyz __init__.py a.py b.py t.py xyz.py 

Dateien init .py, b.py und xyz.py sind leer
Datei a.py:

 import os, sys ROOT_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) if not sys.path or ROOT_DIRECTORY not in sys.path: print 'sys.path is modified in a.py' sys.path.insert(0, ROOT_DIRECTORY) else: print 'sys.path is NOT modified in a.py' print 'sys.path:', sys.path print 'BEFORE import xyz.b' import xyz.b print 'AFTER import xyz.b' 

Datei t.py:

 import os, sys ROOT_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) if not sys.path or ROOT_DIRECTORY not in sys.path: print 'sys.path is modified in t.py' sys.path.insert(0, ROOT_DIRECTORY) else: print 'sys.path is NOT modified in t.py' import xyz.a 

Lauf:

 python a.py 

Ausgabe:

 sys.path is modified in a.py sys.path: ['/home/dmugtasimov/tmp/name-res3', '/home/dmugtasimov/tmp/name-res3/xyz', '/usr/local/lib/python2.7/dist-packages/tornado-2.3-py2.7.egg', '/home/dmugtasimov/tmp/name-res3/xyz', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client'] BEFORE import xyz.b AFTER import xyz.b 

Lauf:

 python -vv a.py 

Ausgabe:

 import xyz # directory /home/dmugtasimov/tmp/name-res3/xyz # trying /home/dmugtasimov/tmp/name-res3/xyz/__init__.so # trying /home/dmugtasimov/tmp/name-res3/xyz/__init__module.so # trying /home/dmugtasimov/tmp/name-res3/xyz/__init__.py # /home/dmugtasimov/tmp/name-res3/xyz/__init__.pyc matches /home/dmugtasimov/tmp/name-res3/xyz/__init__.py import xyz # precompiled from /home/dmugtasimov/tmp/name-res3/xyz/__init__.pyc # trying /home/dmugtasimov/tmp/name-res3/xyz/b.so # trying /home/dmugtasimov/tmp/name-res3/xyz/bmodule.so # trying /home/dmugtasimov/tmp/name-res3/xyz/b.py # /home/dmugtasimov/tmp/name-res3/xyz/b.pyc matches /home/dmugtasimov/tmp/name-res3/xyz/b.py import xyz.b # precompiled from /home/dmugtasimov/tmp/name-res3/xyz/b.pyc 

Lauf:

 python t.py 

Ausgabe:

 sys.path is modified in t.py sys.path is NOT modified in a.py sys.path: ['/home/dmugtasimov/tmp/name-res3', '/home/dmugtasimov/tmp/name-res3/xyz', '/usr/local/lib/python2.7/dist-packages/tornado-2.3-py2.7.egg', '/home/dmugtasimov/tmp/name-res3/xyz', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client'] BEFORE import xyz.b Traceback (most recent call last): File "t.py", line 9, in <module> import xyz.a File "/home/dmugtasimov/tmp/name-res3/xyz/a.py", line 11, in <module> import xyz.b ImportError: No module named b 

Lauf:

 python -vv t.py 

Ausgabe:

 import xyz # directory /home/dmugtasimov/tmp/name-res3/xyz # trying /home/dmugtasimov/tmp/name-res3/xyz/__init__.so # trying /home/dmugtasimov/tmp/name-res3/xyz/__init__module.so # trying /home/dmugtasimov/tmp/name-res3/xyz/__init__.py # /home/dmugtasimov/tmp/name-res3/xyz/__init__.pyc matches /home/dmugtasimov/tmp/name-res3/xyz/__init__.py import xyz # precompiled from /home/dmugtasimov/tmp/name-res3/xyz/__init__.pyc # trying /home/dmugtasimov/tmp/name-res3/xyz/a.so # trying /home/dmugtasimov/tmp/name-res3/xyz/amodule.so # trying /home/dmugtasimov/tmp/name-res3/xyz/a.py # /home/dmugtasimov/tmp/name-res3/xyz/a.pyc matches /home/dmugtasimov/tmp/name-res3/xyz/a.py import xyz.a # precompiled from /home/dmugtasimov/tmp/name-res3/xyz/a.pyc # trying /home/dmugtasimov/tmp/name-res3/xyz/os.so # trying /home/dmugtasimov/tmp/name-res3/xyz/osmodule.so # trying /home/dmugtasimov/tmp/name-res3/xyz/os.py # trying /home/dmugtasimov/tmp/name-res3/xyz/os.pyc # trying /home/dmugtasimov/tmp/name-res3/xyz/sys.so # trying /home/dmugtasimov/tmp/name-res3/xyz/sysmodule.so # trying /home/dmugtasimov/tmp/name-res3/xyz/sys.py # trying /home/dmugtasimov/tmp/name-res3/xyz/sys.pyc # trying /home/dmugtasimov/tmp/name-res3/xyz/xyz.so # trying /home/dmugtasimov/tmp/name-res3/xyz/xyzmodule.so # trying /home/dmugtasimov/tmp/name-res3/xyz/xyz.py # /home/dmugtasimov/tmp/name-res3/xyz/xyz.pyc matches /home/dmugtasimov/tmp/name-res3/xyz/xyz.py import xyz.xyz # precompiled from /home/dmugtasimov/tmp/name-res3/xyz/xyz.pyc # clear[2] __file__ # clear[2] __package__ # clear[2] sys # clear[2] ROOT_DIRECTORY # clear[2] __name__ # clear[2] os sys.path is modified in t.py sys.path is NOT modified in a.py sys.path: ['/home/dmugtasimov/tmp/name-res3', '/home/dmugtasimov/tmp/name-res3/xyz', '/usr/local/lib/python2.7/dist-packages/tornado-2.3-py2.7.egg', '/home/dmugtasimov/tmp/name-res3/xyz', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client'] BEFORE import xyz.b Traceback (most recent call last): File "t.py", line 9, in <module> import xyz.a File "/home/dmugtasimov/tmp/name-res3/xyz/a.py", line 11, in <module> import xyz.b ImportError: No module named b 

Wie Sie sys.path sehen, ist das gleiche für beide Fälle:

 sys.path: ['/home/dmugtasimov/tmp/name-res3', '/home/dmugtasimov/tmp/name-res3/xyz', '/usr/local/lib/python2.7/dist-packages/tornado-2.3-py2.7.egg', '/home/dmugtasimov/tmp/name-res3/xyz', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client'] 

Aber das Verhalten ist anders. Für a.py python sucht paket xyz zuerst, und sie für Modul b drin:

 import xyz # directory /home/dmugtasimov/tmp/name-res3/xyz # trying /home/dmugtasimov/tmp/name-res3/xyz/__init__.so # trying /home/dmugtasimov/tmp/name-res3/xyz/__init__module.so # trying /home/dmugtasimov/tmp/name-res3/xyz/__init__.py # /home/dmugtasimov/tmp/name-res3/xyz/__init__.pyc matches /home/dmugtasimov/tmp/name-res3/xyz/__init__.py import xyz # precompiled from /home/dmugtasimov/tmp/name-res3/xyz/__init__.pyc # trying /home/dmugtasimov/tmp/name-res3/xyz/b.so # trying /home/dmugtasimov/tmp/name-res3/xyz/bmodule.so # trying /home/dmugtasimov/tmp/name-res3/xyz/b.py # /home/dmugtasimov/tmp/name-res3/xyz/b.pyc matches /home/dmugtasimov/tmp/name-res3/xyz/b.py import xyz.b # precompiled from /home/dmugtasimov/tmp/name-res3/xyz/b.pyc 

Mit anderen Worten:

  1. Suche PACKAGE xyz im Verzeichnis sys.path [0] -> GEFUNDEN
  2. Suchmodul b in PACKAGE xyz -> GEFUNDEN
  3. Fortsetzung der Ausführung

Für t.py sucht es nach moduel xyz im selben Verzeichnis wie a.py selbst und dann fehlt das Modul b im Modul xyz:

 # trying /home/dmugtasimov/tmp/name-res3/xyz/xyz.so # trying /home/dmugtasimov/tmp/name-res3/xyz/xyzmodule.so # trying /home/dmugtasimov/tmp/name-res3/xyz/xyz.py # /home/dmugtasimov/tmp/name-res3/xyz/xyz.pyc matches /home/dmugtasimov/tmp/name-res3/xyz/xyz.py import xyz.xyz # precompiled from /home/dmugtasimov/tmp/name-res3/xyz/xyz.pyc 

Mit anderen Worten:

  1. Suchen Sie MODULE xyz im Verzeichnis im selben Verzeichnis wie a.py (oder sys.path [1]?) -> FOUND
  2. Suche MODUL b im MODUL xyz -> NICHT GEFUNDEN
  3. ImportError

So sieht es aus wie wenn "import xyz.b" bahaves unterschiedlich je nachdem, wie a.py ursprünglich als Skript geladen oder aus einem anderen Modul importiert wurde.

UPDATE 3

Ich habe den Vorschlag für die Dokumentation fix: http://bugs.python.org/issue16891

UPDATE 4

Der Grund für das Verhalten, das in UPDATE 2 beschrieben ist, ist für mich jetzt völlig klar.

Http://docs.python.org/2/tutorial/modules.html#intra-package-referenzen

6.4.2. Intra-Paket Referenzen

Die Submodule müssen sich oft aufeinander beziehen. Beispielsweise könnte das Surround-Modul das Echomodul verwenden. In der Tat sind solche Referenzen so häufig, dass die Import-Anweisung zuerst in das enthaltene Paket schaut, bevor sie in den Standard-Modul-Suchpfad schaut. So kann das Surround-Modul einfach das Import-Echo oder den Echo-Import-Echofilter verwenden. Wenn das importierte Modul nicht im aktuellen Paket gefunden wird (das Paket, welches das aktuelle Modul ein Submodul ist), sucht die Import-Anweisung nach einem Top-Level-Modul mit dem angegebenen Namen.

Für "python a.py" "a" gilt nicht als Modul im Paket, sondern für "python t.py" "a" gilt als Modul im Paket "xyz". Deshalb sucht es im ersten Fall nach sys.path, aber im zweiten Fall sucht es im selben Paket (nämlich "xyz") für das Modul namens "xyz" (mit anderen Worten "xyz.xyz")

Sie können leicht sehen, wenn Änderung a.py wie folgt:

Datei a.py:

 import os, sys ROOT_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) if not sys.path or ROOT_DIRECTORY not in sys.path: print 'sys.path is modified in a.py' sys.path.insert(0, ROOT_DIRECTORY) else: print 'sys.path is NOT modified in a.py' print 'sys.path:', sys.path print '__package__', __package__ print 'BEFORE import xyz.b' import xyz.b print 'AFTER import xyz.b' 

Meine Ausgabe war:

 ~/tmp/name-res3/xyz $ python a.py sys.path is modified in a.py sys.path: ['/home/dmugtasimov/tmp/name-res3', '/home/dmugtasimov/tmp/name-res3/xyz', '/usr/local/lib/python2.7/dist-packages/tornado-2.3-py2.7.egg', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client'] __package__ None BEFORE import xyz.b AFTER import xyz.b ~/tmp/name-res3/xyz $ python t.py sys.path is modified in t.py sys.path is NOT modified in a.py sys.path: ['/home/dmugtasimov/tmp/name-res3', '/home/dmugtasimov/tmp/name-res3/xyz', '/usr/local/lib/python2.7/dist-packages/tornado-2.3-py2.7.egg', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client'] __package__ xyz BEFORE import xyz.b Traceback (most recent call last): File "t.py", line 9, in <module> import xyz.a File "/home/dmugtasimov/tmp/name-res3/xyz/a.py", line 12, in <module> import xyz.b ImportError: No module named b 

Danke an @JF Sebastian für den Hinweis auf den richtigen Ort der Dokumentation.

UPDATE 5

Es scheint, dass es ein anderes Problem gibt. Wenn interessiert, bitte, folgen Sie hier Kommentare: http://bugs.python.org/issue16891

  • Python-Authentifizierung mit urllib2
  • Buildozer-Fehler, CalledProcessError (Kivy)
  • Verwenden von Serial auf Python / Win7
  • Gibt es eine "sichere" Teilmenge von Python für die Verwendung als eingebettete Skriptsprache?
  • Pythonstreifen () funktioniert nicht in einer Funktion
  • Wie behandle ich verschachtelte Ausnahmen von verschiedenen Gunicorn-Gabeln?
  • Überspringen aller Unit-Tests, aber eine in Python mit Dekorateure und Metaklassen
  • Finden Sie doppelte Elemente in einer Liste
  • 2 Solutions collect form web for “Warum python findet Modul statt Paket, wenn sie den gleichen Namen haben?”

    Ich vereinfachte das Beispiel von der Frage zu demostrate, dass nur vier Lösungen möglich sind:

    • Expliziter relativer Import from . import some_module from . import some_module oder mit mehr Kommas from ..
    • Relativer Import (ohne "xyz." Bei Verwendung im Paket "xyz")
    • Absoluter Import mit from __future__ import absolute_import (oder verwenden Sie Python 3)
    • Wiederholen Sie niemals den Namen des Pakets der obersten Ebene in einem beliebigen Pfad.

    Welche Lösung ist das Beste? Es hängt von der persönlichen Vorliebe von Python 2 oder 3. Nur die letzte ist schön und universal für alle Pythons. Es war wirklich eine nützliche Frage.


    Xyz / tests / __ init__.py : import xyz.tests.t

    Xyz / tests / t.py :

     import sys print('sys.path = %s' % sys.path) # see that the parent of "xyz" is on sys.path print("importing xyz.tests") import xyz.a 

    Xyz / a.py:

     # solution A: absolute_import by __future__ (or use Python 3) #from __future__ import absolute_import print("importing xyz.a") # solution B: explicit relative import #from . import b # and remove "import xyz.b" # solution C: relative import (not recommended) #import b # and remove "import xyz.b" import xyz.b 

    Xyz / b.py : print("imported xyz.b")

    Xyz / xyz.py : print("Imported xyz.xyz !!!")

    Xyz / __ init__.py : leere Datei


    Alles Mögliche scheitert, zB

     parent_of_xyz=... # The parent directory of "xyz" - absolute path cd $parent_of_xyz python -m xyz.tests.t PYTHONPATH=$parent_of_xyz/xyz python -m unittest tests PYTHONPATH=$parent_of_xyz python xyz/tests/t.py 

    Mit Meldungen wie

     Imported xyz.xyz !!! ... ImportError... 

    Wenn eine Lösung angewendet wird (unkommentiert), arbeiten alle drei Beispiele.

    Es kann vereinfacht werden, ohne ein Unterverzeichnis zu verwenden.

    EDIT: Ich habe gestern viele Tests ausprobiert, aber ich schrieb es unaufhörlich aus verschiedenen Versionen. Entschuldigen Sie, dass es von der Antwort nicht reproduzierbar war. Jetzt ist es behoben .

    Ändern Sie sys.path nicht zu den Problemen, wenn das gleiche Modul unter verschiedenen Namen verfügbar ist. Siehe Fallen für die Unwary .

    Verwenden Sie absolute oder explizite relative Importe statt in den Code und führen Sie Ihre Skripte aus dem Projektverzeichnis. Führen Sie die Tests mit dem vollständigen Namen aus:

     $ python -munittest root.tests.test_1 

    Einige Pakete ändern sys.path intern zB sehen, wie twisted verwendet _preamble.py oder pypys autopath.py . Sie könnten entscheiden, ob ihre Nachteile (Einführung von obskuren Importproblemen) die Überzeugung wert sind (mehr Möglichkeiten, um Ihre Skripte laufen zu lassen). Vermeiden Sie das Ändern von sys.path in einem Code, der als Bibliothek verwendet wird, dh beschränken Sie ihn auf Testmodule und Ihre Befehlszeilen-Skripte.

    Python ist die beste Programmiersprache der Welt.