shi*_*ino 85 python import module
假设我有一个名为的包bar,它包含bar.py:
a = None
def foobar():
print a
Run Code Online (Sandbox Code Playgroud)
并且__init__.py:
from bar import a, foobar
Run Code Online (Sandbox Code Playgroud)
然后我执行这个脚本:
import bar
print bar.a
bar.a = 1
print bar.a
bar.foobar()
Run Code Online (Sandbox Code Playgroud)
这就是我的期望:
None
1
1
Run Code Online (Sandbox Code Playgroud)
这是我得到的:
None
1
None
Run Code Online (Sandbox Code Playgroud)
任何人都能解释我的错误观念吗?
aar*_*ing 82
你在用from bar import a.a成为导入模块的全局范围中的符号(或导入语句出现的任何范围).因此,当您为其分配新值时a,您只需更改哪个值a,而不是实际值.尝试导入bar.py直接与import bar中__init__.py,并通过设置有进行实验bar.a = 1.这样,您实际上正在修改bar.__dict__['a']哪个是a此上下文中的"真实"值.
它有三层融合,但bar.a = 1改变了实际派生a的模块中的值.它不会改变看到的值,因为它存在于实际文件中.您可以设置是否要更改它.bar__init__.pyafoobarfoobarbar.pybar.bar.a
这是使用语句from foo import bar形式的危险之一import:它分为bar两个符号,一个从内部foo开始全局可见,开始指向原始值,另一个符号在import执行语句的范围内可见.更改符号指向的位置不会更改它指向的值.
当reload从交互式解释器尝试模块时,这种东西是杀手.
Eri*_*got 20
这个问题困难的一个原因是,你有一个名为程序bar/bar.py:import bar可导入bar/__init__.py或bar/bar.py,取决于它完成,这使得它有点笨重跟踪哪些a是bar.a.
下面是它的工作原理:
理解发生的事情的关键是要意识到在你的__init__.py,
from bar import a
Run Code Online (Sandbox Code Playgroud)
实际上做了类似的事情
a = bar.a # … with bar = bar/bar.py (as if bar were imported locally from __init__.py)
Run Code Online (Sandbox Code Playgroud)
并定义一个新变量(bar/__init__.py:a如果你愿意的话).因此,您from bar import a在__init__.py绑定的名字bar/__init__.py:a原来的bar.py:a对象(None).这就是为什么你可以做from bar import a as a2的__init__.py:在这种情况下,很显然,你有两个bar/bar.py:a和一个不同的变量名bar/__init__.py:a2(在你的情况下,这两个变量的名称只是碰巧都为a,但他们仍然生活在不同的命名空间:在__init__.py,他们是bar.a和a).
现在,当你这样做
import bar
print bar.a
Run Code Online (Sandbox Code Playgroud)
你正在访问变量bar/__init__.py:a(因为import bar导入你的bar/__init__.py).这是您修改的变量(为1).你没有触及变量的内容bar/bar.py:a.所以当你随后做的时候
bar.foobar()
Run Code Online (Sandbox Code Playgroud)
你叫bar/bar.py:foobar(),它访问的变量a从bar/bar.py,这仍然是None(时foobar()被定义,它绑定变量名一劳永逸的,所以a在bar.pyIS bar.py:a,没有任何其他a的另一模块定义的变量可能有许多a在所有导入的模块变量).因此最后的None输出.
Mar*_*tos 10
换句话说:结果证明这种误解很容易. 它在Python语言参考中被巧妙地定义:使用object而不是symbol.我建议Python语言参考使这更清晰,更少稀疏..
的
from形式不结合模块名称:它通过标识符的列表,看起来它们中的每一个向上在步骤(1)中发现的模块中,并且在本地名称空间中的结合名称对象从而找到.
然而:
导入时,导入导入符号的当前值,并将其添加到定义的命名空间中. 您没有导入引用,您实际上是在导入值.
因此,要获取更新的值i,必须导入一个包含对该符号的引用的变量.
换句话说,导入不像importJAVA中的external声明,C/C++中的声明甚use至PERL中的子句.
相反,Python中的以下语句:
from some_other_module import a as x
Run Code Online (Sandbox Code Playgroud)
是更喜欢在K&R C以下代码:
extern int a; /* import from the EXTERN file */
int x = a;
Run Code Online (Sandbox Code Playgroud)
(警告:在Python的情况下,"a"和"x"本质上是对实际值的引用:你没有复制INT,你正在复制引用地址)
| 归档时间: |
|
| 查看次数: |
38474 次 |
| 最近记录: |