Python 第十亿次相对进口
我来过这里:Python 第十亿次相对进口,python,python-2.7,import,python-2.x,relative-path,Python,Python 2.7,Import,Python 2.x,Relative Path,我来过这里: 还有很多我没有复制的URL,有些在其他网站上,有些在我认为我很快就能找到解决方案的时候 永远反复出现的问题是:在Windows 7、32位Python 2.7.3中,如何解决“在非包中尝试相对导入”消息?我在pep-0328上构建了一个完全相同的软件包副本: package/ __init__.py subpackage1/ __init__.py moduleX.py moduleY.py
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
导入是从控制台完成的
我确实在相应的模块中创建了名为spam和eggs的函数。当然,它不起作用。答案显然在我列出的第四个URL中,但对我来说都是校友。我访问的一个URL上有这样的响应:
相对导入使用模块的name属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它被设置为“main”),则将解析相对导入,就像模块是顶级模块一样,而不管模块在文件系统上的实际位置如何
上面的回答看起来很有希望,但对我来说都是象形文字。所以我的问题是,如何使Python不返回到我的“在非包中尝试相对导入”?有一个答案可能是-m
有人能告诉我为什么Python会给出这个错误消息,它的“非包”是什么意思,为什么以及如何定义“包”,准确的答案用一个幼稚园学生很容易理解的术语来表达。
\uuuu name\uuuu
的变化取决于所讨论的代码是在全局名称空间中运行还是作为导入模块的一部分运行
如果代码未在全局空间中运行,\uuuuuu name\uuuuu
将是模块的名称。如果它在全局名称空间中运行——例如,如果您在控制台中键入它,或者使用python.exe yourscriptnamehere.py作为脚本运行模块,那么\uuuuu name\uuuuuuu
将变为“\uuuu main\uuuuuu”
如果使用uuu name uuu=='uuuu main uuu'
来测试代码是否从全局名称空间运行,您将看到许多带有的python代码,这允许您拥有一个兼作脚本的模块
您是否尝试从控制台进行这些导入 脚本与模块的对比
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
这里有一个解释。简短的版本是,直接运行Python文件和从其他地方导入该文件之间有很大的区别仅仅知道文件所在的目录并不能确定Python认为它所在的包。这还取决于您如何将文件加载到Python中(通过运行或导入)
加载Python文件有两种方法:作为顶级脚本,或作为
模块。如果直接执行某个文件,例如在命令行上键入python myfile.py
,则该文件将作为顶级脚本加载。当在其他文件中遇到import
语句时,它将作为模块加载。一次只能有一个顶级脚本;顶层脚本是您运行以开始工作的Python文件
命名
加载文件时,会为其指定一个名称(该名称存储在其\uuu name\uuu
属性中)。如果它作为顶级脚本加载,则其名称为\uuuuu main\uuuu
。如果它作为模块加载,则其名称为文件名,前面是它所属的任何包/子包的名称,以点分隔
例如,在您的示例中:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
如果导入了moduleX
(注意:已导入,不直接执行),则其名称将为package.subpackage1.moduleX
。如果导入了moduleA
,则其名称将为package.moduleA
。但是,如果直接从命令行运行moduleX
,则其名称将改为\uuuuu main\uuuuu
,如果直接从命令行运行moduleA
,则其名称将为\uuuu main\uuu
。当模块作为顶级脚本运行时,它将丢失其正常名称,而其名称为\uuuuu main\uuuu
不通过模块的包含包访问模块
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
还有一个问题:模块的名称取决于它是“直接”从它所在的目录导入的,还是通过包导入的。只有在目录中运行Python,并尝试在同一目录(或其子目录)中导入文件时,这才有区别。例如,如果您在目录package/subpackage1
中启动Python解释器,然后执行import moduleX
,那么moduleX
的名称将只是moduleX
,而不是package.subpackage1.moduleX
。这是因为当以交互方式输入解释器时,Python将当前目录添加到其搜索路径中;如果它在当前目录中找到要导入的模块,它将不知道该目录是包的一部分,包信息也不会成为模块名称的一部分
一种特殊情况是,如果您以交互方式运行解释器(例如,只需键入python
并开始动态输入python代码)。在这种情况下,该交互式会话的名称是\uuuuu main\uuuu
下面是错误消息的关键点:如果模块名称没有点,则不认为它是包的一部分。文件在磁盘上的实际位置并不重要。重要的是它的名字是什么,它的名字取决于你如何加载它
现在,请看您在问题中引用的内容:
相对导入使用模块的name属性来确定该模块在包层次结构中的位置。如果模块名称不包含任何包信息(例如设置为“main”),则将解析相对导入,就像模块是顶级模块一样,regardles
#!/usr/bin/env python3
if __name__ == '__main__' and __package__ is None:
from os import sys, path
# __file__ should be defined in this case
PARENT_DIR = path.dirname(path.dirname(path.abspath(__file__)))
sys.path.append(PARENT_DIR)
from subpackage1.moduleX import *
from __future__ import print_function # only when showing how this works
if __package__:
print('Package named {!r}; __name__ is {!r}'.format(__package__, __name__))
from .fileA import f1, f2
from .fileB import Class3
else:
print('Not a package; __name__ is {!r}'.format(__name__))
# these next steps should be used only with care and if needed
# (remove the sys.path manipulation for simple cases!)
import os, sys
_i = os.path.dirname(os.path.abspath(__file__))
if _i not in sys.path:
print('inserting {!r} into sys.path'.format(_i))
sys.path.insert(0, _i)
else:
print('{!r} is already in sys.path'.format(_i))
del _i # clean up global name space
from fileA import f1, f2
from fileB import Class3
... all the code as usual ...
if __name__ == '__main__':
import doctest, sys
ret = doctest.testmod()
sys.exit(0 if ret.failed == 0 else 1)
$ python2 lib.foo
$ python3 lib.foo
Package named 'lib'; __name__ is '__main__'
$ python2 lib.foo
Package named 'lib'; __name__ is 'lib.foo'
Package named 'lib'; __name__ is '__main__'
$ python3 lib.routine
Package named 'lib'; __name__ is 'lib.foo'
[...]/runpy.py:125: RuntimeWarning: 'lib.foo' found in sys.modules
after import of package 'lib', but prior to execution of 'lib.foo';
this may result in unpredictable behaviour
warn(RuntimeWarning(msg))
Package named 'lib'; __name__ is '__main__'
import os, sys
_i = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if _i not in sys.path:
sys.path.insert(0, _i)
else:
_i = None
from sub.fileA import f1, f2
from sub.fileB import Class3
if _i:
sys.path.remove(_i)
del _i
from .. import foo
if __package__ is None or __package__ == '':
# uses current directory visibility
import foo
else:
# uses current package visibility
from . import foo
if __name__ == '__main__':
# run test code here...
# import any site-lib modules first, then...
import sys
parent_module = sys.modules['.'.join(__name__.split('.')[:-1]) or '__main__']
if __name__ == '__main__' or parent_module.__name__ == '__main__':
from codex import Codex # these are in same folder as module under test!
from dblogger import DbLogger
else:
from .codex import Codex
from .dblogger import DbLogger
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
import sys
from os.path import dirname, basename
if __package__ is None:
sys.path.insert(0, '..')
__package__ = basename(dirname(sys.argv[0]))
from . import your_module
your_module
your_module.py