gpt4 book ai didi

python - 在循环引用下理解python的import *机制

转载 作者:行者123 更新时间:2023-11-28 22:45:28 31 4
gpt4 key购买 nike

我为了回答aquestion posted here on SO而玩示例,发现很难理解python的import *破坏作用域的机制。
首先是一点上下文:这个问题不涉及实际问题;我很清楚from foo import *是不受欢迎的(这是正确的),而且我明白,这是因为代码中的原因比清晰性更深。我在这里的兴趣是理解导致循环不良行为的机制。换句话说,我理解观察到的行为是预期的;我不明白为什么。
我无法理解的情况是,当使用导入模块(import *)引用导入模块(b)时出现的问题。当导入模块使用a或不使用*时,我设法观察到行为上的细微差异,但总体(不良)行为是相同的。我找不到任何明确的解释,无论是在文件中还是在这样。
通过对作用域上可用内容的调查,我构建了一个小示例,根据上述问题和我在SO和其他地方进行的一些搜索,说明了其内容的差异。我尽量简洁地演示。下面的所有代码和实验都是用Python2.7.8完成的。
工作场景
首先是包含包含一个类的平凡模块的平凡模块,*

class A:
pass

客户端代码的第一个变体,导入模块A, a.py
from pprint import pprint

def dump_frame(offset=0):
import sys
frame = sys._getframe(1+offset)
d = frame.f_globals
d.update(frame.f_locals)
return d

print 'before import v1'
pprint (dump_frame())

import a

print 'after import v1'
pprint (dump_frame())
print a.A()

同一代码的第二个变体,从模块导入 b_v1.py*
from pprint import pprint

def dump_frame(offset=0):
import sys
frame = sys._getframe(1+offset)
d = frame.f_globals
d.update(frame.f_locals)
return d

print 'before import v2'
pprint (dump_frame())

from a import *

print 'after import v2'
pprint (dump_frame())
print A()

在导入之前同时运行 ab_v2.py会产生相同的输出,并且两者都能够按预期实例化。然而,正如预期的那样,在进口之后,它们又有所不同。我强调了区别:
b_v1,在范围内
'a': <module 'a' from '.../stackoverflow/instance/a.py'>

b_v2没有,但是
'A': <class a.A at 0x...>

导入前后,作用域都包含设置为 b_v1.pyb_v2.py
两个变量都成功地实例化了 __builtins__
不工作的情况
有趣的行为是当改变 <module '__builtin__' (built-in)>以包含对 A的循环引用时(在 a.pyb变体中)。
调整代码:
from b_v1 import *
class A:
pass

(简而言之,只显示了一个 b_v1的情况;显然,在 b_v2的情况下,导入是针对这个模块的,而不是针对 a.py
在我用循环引用对场景中范围内容的观察中,我看到:
在这两种变体中,在导入 a.py之前, b_v2.py与上述情况相似。但是,在导入之后,它被更改并包含
“算术错误”:,
'断言错误':,
'属性错误':,
...
在这里粘贴的时间是不必要的。
更改的 b_v1.py出现两次。我可以理解这是导入的结果,如果代码在函数中,则可能不会发生这种情况。
在variant a中,模块 __builtins__出现在范围中;它出现在variant dict中。
在这两种变体中, __builtins__的实例化都失败。考虑到在variant b_v2中,该模块存在于作用域中(因此,我假设已成功导入),我本来希望能够实例化 a。事实并非如此。但也有区别:在 b_v1情况下,它以 A失败,而对于 b_v1,失败是a A。在后一种情况下,无论我是否尝试实例化为 b_v1.py(如工作示例中所示)的 AttributeError: 'module' object has no attribute 'A',它总是相同的错误。
总结我的问题:
一个圆形的物体通过什么机械装置把望远镜弄乱了?
为什么在b v1的情况下不能实例化 b_v2.py,尽管模块在作用域中?

最佳答案

Python模块自上而下执行。导入语句和其他语句一样是可执行的。当import语句运行时,它会执行以下操作(为了便于说明,请参阅language reference以了解详细信息):
检查模块是否在sys.modules中列出。如果是,请立即归还
查找模块(通常但不总是通过搜索文件系统)。
sys.modules中为模块创建一个空条目,名称空间为空。
在新创建的命名空间中自上而下执行模块。
假设我们有这样的文件:
a.py

from b import *
foo = object()

b.py
from a import *
print(repr(foo))

进一步假设 a.py首先被导入。让我们一行一行地看一下:
其他人导入 a。在我们开始执行之前,对 a的引用存储在 sys.modules['a']中。
a.py运行 from b import *。这将转换为“ import b,然后将 b命名空间中的所有内容获取到 a命名空间中。”
Python在 sys.modules['b']
b.py运行 from a import *。Python导入 a
a以来,立即导入 sys.modules['a']返回。
由于 a.py尚未执行 foo = object()a.foo尚未存在,因此不能倾倒到 b命名空间中。
b.py在上崩溃。

关于python - 在循环引用下理解python的import *机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28551513/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com