如果python具有相同的名称,为什么python会找到模块而不是包?

时间:2013-01-06 15:21:05

标签: python import module package sys.path

这是我的目录结构:

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

文件内容: 的根/测试/ _ 初始化 _。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

根/测试/ test_1.py

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

root / _ init _。py - 空白 的根/ 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

根/ extra.py

class Class3(object):
    pass

根/ 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的文件。“

这意味着python应该查看sys.path索引0条目,获取路径'/ home / dmugtasimov / tmp / name-res'并找到名为root的包,然后在此包中搜索名为extra的模块。但是它会在/ home / dmugtasimov / tmp / name-res / root /目录中搜索模块root,然后尝试在其中查找名为extra的内容。它发生了什么?它不与官方文件相矛盾吗?或者是搜索与模块不同的包的规则?如果是这样,这些规则是否涵盖在文档中?

更新

我把它放在这里以便更好地格式化 如需进一步调查,请执行以下操作:

  1. 删除root.pyc
  2. 将root.py重命名为root2.py
  3. 运行python -vv -m unittest tests.test_1
  4. # 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
    

    对于最初的4次尝试,python似乎忽略了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]中搜索PACKAGE xyz - &gt;结果
    2. 在PACKAGE xyz中搜索模块b - &gt;结果
    3. 继续执行
    4. 对于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. 在目录中搜索MODULE xyz与a.py(或sys.path [1]相同的目录?) - &gt;结果
      2. 在MODULE xyz中搜索MODULE b - &gt;没找到
      3. 的ImportError
      4. 所以看起来“import xyz.b”bahaves会有所不同,具体取决于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。包内参考

             

        子模块通常需要相互引用。例如,   环绕声模块可能使用echo模块。实际上,这样的参考   是如此常见,导入语句首先在包含中查找   在查看标准模块搜索路径之前打包。就这样   环绕模块可以简单地使用import echo或echo import   echofilter。如果在当前包中找不到导入的模块   (当前模块是子模块的包),导入   statement查找具有给定名称的顶级模块。

        对于“python a.py”,“a”不被视为包中的模块,但对于“python t.py”,“a”被视为包“xyz”中的模块。因此,在第一种情况下,它根据sys.path进行搜索,但在第二种情况下,它在同一个包(即“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
        

        感谢@ J.F。塞巴斯蒂安指出了正确的文件地点。

        更新5

        似乎还有另一个问题。如果有兴趣,请点击此处的评论:http://bugs.python.org/issue16891

2 个答案:

答案 0 :(得分:3)

当相同模块以不同名称提供时,请勿修改sys.path导致问题。请参阅Traps for the Unwary

在代码中使用绝对或显式相对导入,并从项目目录运行脚本。使用全名运行测试:

$ python -munittest root.tests.test_1

有些软件包会在内部修改sys.path,例如,查看twisted如何使用_preamble.py或pypy的autopath.py。您可以决定它们的缺点(引入模糊的导入问题)是否值得花时间(允许运行脚本的更多方法)。避免在用作库的代码中修改sys.path,即将其限制为测试模块和命令行脚本。

答案 1 :(得分:3)

我简化了问题的例子,说明只有四个解决方案是可能的:

  • 明确的相对导入from . import some_module或更多逗号from ..
  • 相对导入(如果在“xyz”包中使用,则不使用“xyz。”)
  • 使用from __future__ import absolute_import进行绝对导入(或使用Python 3)
  • 不要在其中的任何路径中重复包的顶级可导入名称。

最好的解决方案是什么?它取决于Python 2或3的个人偏好。只有最后一个对所有Pythons都很好并且通用。这真是个有用的问题。


xyz / tests / __ init __。py import xyz.tests.t

<强> XYZ /测试/ 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 :空文件


一切皆有可能失败,例如

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

如果应用了任何解决方案(取消注释),则所有三个示例都有效。

不使用任何子目录可以更简化。

编辑:我昨天尝试了很多测试,但是我从不同的版本中不加思索地写了。请原谅我答案是不可复制的。现在它已修复