如果模块的名称相同,为什么python会查找模块而不是包?
以下是我的目录结构:如果模块的名称相同,为什么python会查找模块而不是包?,python,import,module,package,sys.path,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 文件内容: root/tests/_init.py root/tests/test_1.py root/\u init.py-空
/home/dmugtasimov/tmp/name-res
root
tests
__init__.py
test_1.py
__init__.py
classes.py
extra.py
root.py
文件内容:
root/tests/_init.py
root/tests/test_1.py
root/\u 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
class Class3(object):
pass
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
root/extra.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
class Class3(object):
pass
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
root/root.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
class Class3(object):
pass
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文档: 导入名为spam的模块时,解释器首先搜索具有该名称的内置模块。如果未找到,则在变量sys.path给定的目录列表中搜索名为spam.py的文件 这意味着python应该查看sys.path索引0条目,获取路径“/home/dmugtasimov/tmp/name res”,找到名为root的包,然后在此包中搜索名为extra的模块。但它在/home/dmugtasimov/tmp/name res/root/目录中搜索模块根,然后尝试在其中查找名为extra的内容。发生了什么事?这与官方文件不矛盾吗?或者搜索包的规则与模块的规则不同?如果是,这些规则是否包含在文档中 更新 我把它放在这里是为了更好地格式化。
为了进一步调查,请执行以下操作:
/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'
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'
文件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
运行:
输出:
运行:
输出:
运行:
输出:
输出:
但行为是不同的。对于a.py,python首先搜索包xyz,然后搜索其中的模块b:
换言之:
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'
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在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包”,
“/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info”,
“/usr/lib/python2.7/dist包”,
“/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”]
__包\无
在导入xyz.b之前
导入xyz.b后
~/tmp/name-res3/xyz$python t.py
sys.path在t.py中修改
sys.path未在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包”,
“/usr/local/lib/python2.7/dist-packages/setuptools-0.6c11-py2.7.egg-info”,
“/usr/lib/python2.7/dist包”,
“/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”]
__包_xyz
在导入xyz.b之前
回溯(最近一次呼叫最后一次):
文件“t.py”,第9行,在
导入xyz.a
文件“/home/dmugtasimov/tmp/name-res3/xyz/a.py”,第12行,在
导入xyz.b
ImportError:没有名为b的模块
感谢@J.F.Sebastian指出了正确的文档位置
更新5
似乎还有另一个问题。如果有兴趣,请按照此处的注释进行操作:请勿修改
sys.path
当同一模块以不同名称提供时,会导致问题。看
在代码中使用绝对或显式相对导入,并从项目目录运行脚本。使用全名运行测试:
$ python -munittest root.tests.test_1
某些软件包在内部修改系统路径,例如。,
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: ['/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']
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
# 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
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
$ python -munittest root.tests.test_1
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
# 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
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...