从Python中的相对路径导入:奇怪的行为

哈里乌斯

据我从了解Python文档from package import x声明应只约束x,而不是package到当前的命名空间。但在实践中,如果package是一个相对的名字,它有时也必然!

让我举一个例子。考虑以下文件层次结构:

root/
  package/
    __init__.py
    subpackage/
      __init__.py

子包/__init__.py:

foo = 42

包/__init__.py:

from os import name
from .subpackage import foo

print(globals().get('name'))
print(globals().get('os'))
print(globals().get('foo'))
print(globals().get('subpackage'))

现在让我们从root目录运行python(v2或v3)解释器并执行

>>> import package

前三行输出是可预测的:

posix
None
42

但是最后一个<module 'package.subpackage' ...>不是None而不是,这使我有些困惑。

我错过了什么吗?这是预期的行为吗?是什么原因?


在这种情况下,这种情况对我来说似乎更奇怪:

root/
  __init__.py  # Empty.
  package/
    __init__.py
  another_package/
    __init__.py

another_package / __ init__.py:

bar = 33

包/__init__.py:

from ..another_package import bar

print(globals().get('another_package'))

现在,我在根目录之外运行此命令

>>> import root.package
None  # OK.
>>> dir(root.package)
['__builtins__', ..., '__path__', 'bar']  # OK.
>>> dir(root)
['__builtins__', ..., '__path__', 'another_package', 'package']  # What?!

为什么another_package出现在dir(root)

阿什巴

重要的是,模块最多只能加载一次(除非明确地重新加载了模块)。如果将一个模块导入多个模块,则所有模块都引用同一模块对象例如:

模块M.py

bar = 10

模块A.py

import M
M.bar = 4

模块B.py

import M
M.bar = 6

所以:

>>> import M
>>> M.bar
10
>>> import A
>>> M.bar  # A is referencing the same M module object!!
4
>>> import B
>>> M.bar # B is referencing the same M module object!!
6

现在,from ..another_package import bar执行该语句时,它基本上等效于execute from root.another_package import bar由于another_package确实是root包中的模块,所以该语句成功执行,并产生以下效果(可能还有更多效果,但是为此,我们将重点放在这3个方面):

  1. root加载如果以前装(它的__init__.py运行)
  2. bar 导入到当前名称空间
  3. another_package作为属性添加到root模块对象

一些开发人员并不完全了解第1项和第3项。

回到您的问题:让我们import root.package按顺序查看执行时会发生什么

  1. root__init__.py已运行(因为root尚未加载)
  2. package__init__.py已运行(因为package尚未加载)
  3. from ..another_package import bar执行具有上述副作用的程序,最明显的是(是,对象。每个模块只有一个,还记得吗?)添加root了属性的模块对象another_package

这就解释了为什么another_package在出现rootdir

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Python从相对路径导入错误

来自分类Dev

File / FileInputStream相对路径的奇怪行为

来自分类Dev

包括具有相对路径的奇怪行为

来自分类Dev

在 Python 中调用相对路径

来自分类Dev

python模块导入-相对路径问题

来自分类Dev

Python-os.system调用中的相对路径

来自分类Dev

在python中更改目录,相对路径

来自分类Dev

Python:模块中相对路径的使用

来自分类Dev

python中的相对路径几个文件夹

来自分类Dev

Python-os.system调用中的相对路径

来自分类Dev

Python如何管理相对路径

来自分类Dev

相对路径方法(Python)

来自分类Dev

Django设置中的相对路径

来自分类Dev

Xlwings Pythonpath中的相对路径

来自分类Dev

CodeLite:makefile中的相对路径

来自分类Dev

在Twig中捆绑的相对路径

来自分类Dev

jsp中的相对路径

来自分类Dev

Flask中的相对路径

来自分类Dev

在tomcat中传递相对路径

来自分类Dev

Xlwings Pythonpath中的相对路径

来自分类Dev

HTML文件中的相对路径

来自分类Dev

doctests 中的稳健相对路径

来自分类Dev

SystemJS和ES模块导入的相对路径

来自分类Dev

如何合并从相对路径导入的类型?

来自分类Dev

从子目录或相对路径导入包

来自分类Dev

使用相对路径导入Spring bean定义文件

来自分类Dev

如何使用相对路径从不同目录导入python脚本?

来自分类Dev

如何从另一个目录导入具有相对路径的 Python 模块?

来自分类常见问题

如何避免在Angular 2中使用相对路径较长的导入?