10

これが私のディレクトリ構造です:

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

ファイルの内容: 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-の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

次の出力が得られます:

$ 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

問題は、Pythonインタープリターがパッケージまたはモジュールを検索するために使用する順序です。

$ 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...

Pythonのドキュメントhttp://docs.python.org/2/tutorial/modules.html#the-module-search-pathによると:「spamという名前のモジュールがインポートされると、インタプリタは最初に組み込みモジュールを検索します。その名前。見つからない場合は、変数sys.pathで指定されたディレクトリのリストでspam.pyという名前のファイルを検索します。」</ p>

これは、Pythonがsys.pathインデックス0エントリを調べ、パス'/ home / dmugtasimov / tmp / name-res'を取得し、rootという名前のパッケージを見つけてから、このパッケージでextraという名前のモジュールを検索する必要があることを意味します。ただし、代わりに/ home / dmugtasimov / tmp / name-res / root /ディレクトリでモジュールルートを検索し、その中にextraという名前の何かを見つけようとします。それはどうなりますか?公式文書と矛盾しませんか?または、パッケージを検索するためのルールはモジュールの場合とは異なりますか?もしそうなら、これらのルールはドキュメントのどこかでカバーされていますか?

アップデート

書式設定を改善するためにここに配置しました。
さらに調査するには、次のようにします。

  1. root.pycを削除します
  2. root.pyの名前をroot2.pyに変更します
  3. python -vv -munittesttests.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

Pythonは最初の4回の試行でのみsys.pathを無視しているようです。

更新2

簡略化されたバージョン:

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

ファイルinit.py、b.py、xyz.pyは空です
ファイル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'

ファイル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

走る:

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',
 '/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

走る:

python -vv a.py

出力:

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

走る:

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',
 '/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

走る:

python -vv t.py

出力:

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

ご覧のとおり、sys.pathはどちらの場合も同じです。

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']

しかし、動作は異なります。a.pyの場合、Pythonは最初にパッケージxyzを検索し、その中のモジュールbを検索します。

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

言い換えると:

  1. ディレクトリsys.path[0]->FOUNDでPACKAGExyzを検索します
  2. PACKAGExyz->FOUNDでモジュールbを検索します
  3. 実行を継続

t.pyの場合、a.py自体と同じディレクトリでmoduel xyzを検索し、モジュールxyzでモジュールbを見つけることができません。

# 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

言い換えると:

  1. a.py(またはsys.path [1]?)->FOUNDと同じディレクトリ内のディレクトリでMODULExyzを検索します
  2. MODULExyzでMODULEbを検索->見つかりません
  3. ImportError

したがって、「import xyz.b」baの動作は、a.pyが最初にスクリプトとして読み込まれた方法、または別のモジュールからインポートされた方法によって異なるように見えます。

更新3

ドキュメント修正の提案を提出しました:http://bugs.python.org/issue16891

更新4

UPDATE 2で説明されている動作の理由は、今では完全に明らかです。

http://docs.python.org/2/tutorial/modules.html#intra-package-references

6.4.2。パッケージ内リファレンス

多くの場合、サブモジュールは相互に参照する必要があります。たとえば、サラウンドモジュールはエコーモジュールを使用する場合があります。実際、このような参照は非常に一般的であるため、importステートメントは、標準のモジュール検索パスを調べる前に、最初に含まれているパッケージを調べます。したがって、サラウンドモジュールは単にimportechoまたはfromechoimportechofilterを使用できます。インポートされたモジュールが現在のパッケージ(現在のモジュールがサブモジュールであるパッケージ)に見つからない場合、importステートメントは指定された名前の最上位モジュールを探します。

「pythona.py」の場合、「a」はパッケージ内のモジュールとは見なされませんが、「pythont.py」の場合、「a」はパッケージ「xyz」内のモジュールと見なされます。したがって、最初のケースではsys.pathに従って検索しますが、2番目のケースでは、同じパッケージ(つまり、「xyz」)内で「xyz」(つまり「xyz.xyz」)という名前のモジュールを検索します。

次のようにa.pyを変更するかどうかを簡単に確認できます。

ファイル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'

私の出力は次のとおりです。

~/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

ドキュメントの適切な場所を指摘してくれた@JFSebastianに感謝します。

更新5

別の問題があるようです。興味がある場合は、ここのコメントに従ってください:http: //bugs.python.org/issue16891

4

2 に答える 2

3

質問の例を簡略化して、4つの解決策しか考えられないことを示しました。

  • 明示的な相対インポートfrom . import some_moduleまたはより多くのコンマfrom ..
  • 相対インポート(パッケージ「xyz」で使用されている場合は「xyz」なし)
  • from __future__ import absolute_importを使用した(またはPython 3を使用した)絶対インポート
  • パッケージ内のパスで、パッケージの最上位のインポート可能な名前を繰り返さないでください。

どのソリューションが最適ですか?それはPython2または3の個人的な好みに依存します。最後のものだけがすべてのPythonにとって素晴らしく普遍的です。本当に便利な質問でした。


xyz / tests / __ init __。pyimport 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.pyprint("imported xyz.b")

xyz / xyz.pyprint("Imported xyz.xyz !!!")

xyz / __ init __。py:空のファイル


可能なすべてが失敗します、例えば

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

のようなメッセージで

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

いずれかのソリューションが適用された場合(コメントなし)、3つの例すべてが機能します。

サブディレクトリを使用せずに、より単純化できます。

編集: 私は昨日多くのテストを試しましたが、異なるバージョンから一貫性のない書き方をしました。答えからは再現できなかったので失礼します。今では修正されています。

于 2013-01-06T22:36:39.360 に答える
3

sys.path同じモジュールが異なる名前で使用できる場合は、変更しないでください。問題が発生します。不注意の罠を参照してください。

コードでは代わりに絶対または明示的な相対インポートを使用し、プロジェクトディレクトリからスクリプトを実行します。フルネームを使用してテストを実行します。

$ python -munittest root.tests.test_1

一部のパッケージはsys.path内部的に変更されます。たとえば、twisteduses_preamble.pyまたはpypyのを参照してくださいautopath.py。それらの欠点(あいまいなインポートの問題の導入)が便利な価値があるかどうかを判断できます(スクリプトを実行するためのより多くの方法が許可されています)。ライブラリとして使用されるコードを変更することは避けてくださいsys.path。つまり、テストモジュールとコマンドラインスクリプトに限定してください。

于 2013-01-06T19:53:12.473 に答える