加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

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

发布时间:2020-12-20 13:47:51 所属栏目:Python 来源:网络整理
导读:据我所知,从 python docs开始,from package import x语句应该只将x,而不是package绑定到当前命名空间. 但实际上,如果包是一个相对的名字,它有时也受到约束! 让我举个例子.请考虑以下文件层次结构: root/ package/ __init__.py subpackage/ __init__.py 分
据我所知,从 python docs开始,from package import x语句应该只将x,而不是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'))

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

>>> import package

前三条输出线是可预测的:

posix
None
42

但最后一个是< module'package.subpackage'...>而不是没有,这让我感到困惑.

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

在这种情况下,我的情况似乎更加奇怪:

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

现在我在root之外运行它:

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

为什么another_package出现在dir(root)中?

解决方法

实现模块最多加载一次非常重要(除非它们明确地为 reloaded).如果在多个模块中导入模块,则所有模块引用相同的模块对象.例如.:

模块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

现在,当执行..another_package导入栏中的语句时,它基本上等同于从root.another_package导入栏执行.由于another_package确实是root包中的一个模块,因此该语句会成功,并产生以下效果(可能会有更多,但为了这个目的,让我们关注这些3):

>如果以前没有加载root,则加载root(运行’__init__.py’)
> bar被导入当前名称空间
> another_package作为属性添加到根模块对象

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

回到你的问题:让我们看看在执行import root.package时会发生什么,顺序如下:

> root的__init__.py运行(因为root还没有加载)
>包的__init__.py正在运行(因为包尚未加载)
> from ..another_package导入栏执行有上面提到的副作用,最值得注意的是(是.对象.每个模块只有一个,记得吗?)root的模块对象添加了属性another_package.

这解释了为什么another_package出现在root的目录中.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读