Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 循环输入混淆_Python_Python 2.7 - Fatal编程技术网

Python 循环输入混淆

Python 循环输入混淆,python,python-2.7,Python,Python 2.7,我有三个文件: 1) 1.py 2) 2.py 3) 3.py 当我运行命令python two.py时,我得到: [1, 2] [1, 2] [1, 2, 3] [1, 2, 3] 当我运行命令python one.py时,我得到: [1, 2] [1, 2] [1, 2, 3] [1, 2, 3] 请任何人解释一下为什么我会得到这个输出?我越深入这个兔子洞,它就越疯狂。在玩了一会儿之后,我想我对这里到底发生了什么有了一些想法,尽管我仍然不清楚其中的一些原因 import x和from

我有三个文件:

1) 1.py

2) 2.py

3) 3.py

当我运行命令python two.py时,我得到:

[1, 2]
[1, 2]
[1, 2, 3]
[1, 2, 3]
当我运行命令python one.py时,我得到:

[1, 2]
[1, 2]
[1, 2, 3]
[1, 2, 3]

请任何人解释一下为什么我会得到这个输出?

我越深入这个兔子洞,它就越疯狂。在玩了一会儿之后,我想我对这里到底发生了什么有了一些想法,尽管我仍然不清楚其中的一些原因

import x
from x import y
之间存在根本区别。在这两种情况下,将运行文件
x
,并执行其中的代码-包括任何
print
语句,这是有意义的。如果使用
import x
,则执行文件
x
,保留其命名空间(包括任何函数或变量定义),并在当前文件的命名空间中包含指向模块
x
的链接。如果使用“从x导入y”中的
,则执行文件
x
,然后将
y
的副本粘贴到当前文件的命名空间中。你基本上是在那个时间点拍下两张
的快照;
two
以后所做的任何更改都不会反映在
two

让我们来看看翻译:

>>> execfile("two.py")     # This lets us run the file and keep the namespace
[1, 2]
[1, 2]
>>> id(test)
47312858429416
>>> id(three.test)
47312858429128
在本例中,
test
是由
two.py
创建的变量。由于ID不同,我们可以看到
three
模块创建了
test
的副本,而不是引用实际对象

现在,我们可以遵循
python two.py
的程序逻辑。我们首先创建
test=[1,2]
。然后执行
three.py
。此时,我们有来自两个导入测试的行
,它将自动运行
two.py
,这将执行
print
语句(导致
[1,2]
)。这还将制作一份
test
的本地副本,供
three
使用。然后,
three
模块继续并追加3,但它只在其本地副本
test
中追加3。然后我们返回到
two.py
继续执行。当我们打印
test
时,我们正在打印它的本地副本,
three
从未修改过。这就是我们第二次得到
[1,2]
的原因

所以这里是它变得棘手的地方

再次查看上面的
execfile
代码,并将其与下面的代码进行比较,在下面的代码中,我没有执行
python two.py
,而是运行
import two

>>> import two
[1, 2, 3]
>>> two.test
[1, 2, 3]
>>> two.three.test
[1, 2, 3]
>>> id(two.test)
47787298457576
>>> id(two.three.test)
47787298457576
当我看到它的时候,我的大脑爆炸了,原因有两个。首先:我们不再打印两次,只打印一次。第二:
three
模块不再有单独的
test
副本;它现在指的是与
two
完全相同的对象

我得出的结论是如果导入
two.py
而不是将其作为主文件执行,Python将自动解析循环引用,将
test
对象链接在一起,并防止
two
多次执行。
two
尝试导入时,
two
检测到它将再次被导入,而不是再次执行该代码,它只需将它的
test
副本交给
twree
。不管怎么说,我就是这样理解的

考虑这一点是有意义的,因为否则您可能会得到一个无限递归循环。我有点惊讶,Python不仅仅因为用户尝试这种循环怪癖而打了他们一巴掌,因为它会抓住其他类似的导入问题,但这也是一种很好的处理方法

但这解释了python one.py的不同行为。如果您查看两个导入测试中的
发生了什么,我们似乎看到的是
two
中的“导入”行为,而不是“执行”行为。完成该行代码后,
two
包含一个
test
对象,该对象包含
[1,2,3]
,并打印了一次。然后将其复制到
one
的命名空间中,并再次打印。这就是为什么我们会有这种奇怪的行为

So tl;dr:Python将根据您是正常执行文件还是导入文件来执行不同的代码。我们运行
two
的方式不同,这一切都不同。但是不要依赖Python以合理的方式解析循环引用;对我来说,这就像是在玩系统游戏,大多数时候会有更好的方法来设计你的程序,而不必处理这种混乱


有了这个,我要休息一下。

我非常好奇您的用例是什么。@TheSoundDefense感谢您指出我的错误。我正在读一篇关于flask项目组织的文章()。它们有相似的代码。我理解
python two.py
的行为,但我不理解
test
的新值如何一直到
one.py
。我不想给出半个答案://声音防御如果答案不太长,请与我分享你的智慧:)我认为你的答案会帮助我。谢谢!这就像火箭科学:)@warmsspringwinds这是迄今为止我所做的最令人困惑的与Python相关的事情。但至少我表现出了我的理智。
>>> import two
[1, 2, 3]
>>> two.test
[1, 2, 3]
>>> two.three.test
[1, 2, 3]
>>> id(two.test)
47787298457576
>>> id(two.three.test)
47787298457576