为什么我可以在Python for循环中为迭代器和序列使用相同的名称? [英] Why can I use the same name for iterator and sequence in a Python for loop?

查看:148
本文介绍了为什么我可以在Python for循环中为迭代器和序列使用相同的名称?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这更多的是一个概念性的问题。我最近在Python中看到了一段代码(它在2.7中工作,也可能在2.5中运行),其中 for 循环使用相同的名称这两个列表正在迭代和列表中的项目,这使我觉得既是不好的做法,也不应该根本不工作。



例如:

  x = [1,2,3,4,5] 
for x in x:
print x
print x

收益率:

  1 
2
3
4
5
5

现在,对于我来说最后打印的值是从循环中分配给x的最后一个值,但是我不明白为什么能够为循环的的两个部分使用相同的变量名称,并使其功能符合预期。他们在不同的范围?什么是在引擎盖下,允许像这样的工作?

解决方案

什么是 dis 告诉我们:

  Python 3.4.1(默认,2014年5月19日,13:10:29)$在darwin 
上输入help,copyright,credits或license以获取更多信息。
>>>从dis进口dis
>>> dis(x = [1,2,3,4,5]
... for x in x:
... print(x)
... print x))

1 0 LOAD_CONST 0(1)
3 LOAD_CONST 1(2)
6 LOAD_CONST 2(3)
9 LOAD_CONST 3(4) )
12 LOAD_CONST 4(5)
15 BUILD_LIST 5
18 STORE_NAME 0(x)

2 21 SETUP_LOOP 24(至48)
24 LOAD_NAME 0(x)
27 GET_ITER
>> (x)

3 34 LOAD_NAME 1(打印)
37 LOAD_NAME 0(x)
40 CALL_FUNCTION 1( 1位置,0个关键字对)
43 POP_TOP
44 JUMP_ABSOLUTE 28
>> 47 POP_BLOCK

4>> 48 LOAD_NAME 1(打印)
51 LOAD_NAME 0(x)
54 CALL_FUNCTION 1(1位置,0个关键字对)
57 POP_TOP
LOAD_CONST 5(无)
61 RETURN_VALUE

关键位是第2和第3部分 - 我们从 x 24 LOAD_NAME 0(x)),然后我们得到它的迭代器( 27 GET_ITER )并开始遍历它( 28 FOR_ITER )。 Python 永远不会再次加载迭代器。除此之外:这样做是没有任何意义的,因为它已经有了迭代器,并且作为 Python规范的第7.3节实际上需要这样的行为)。
$ b

当名称 x 被覆盖,指向列表中的每个值,以前称为 x Python找到迭代器没有任何问题,因为它永远不需要再次查看名称 x 来完成迭代协议。


This is more of a conceptual question. I recently saw a piece of code in Python (it worked in 2.7, and it might also have been run in 2.5 as well) in which a for loop used the same name for both the list that was being iterated over and the item in the list, which strikes me as both bad practice and something that should not work at all.

For example:

x = [1,2,3,4,5]
for x in x:
    print x
print x

Yields:

1
2
3
4
5
5

Now, it makes sense to me that the last value printed would be the last value assigned to x from the loop, but I fail to understand why you'd be able to use the same variable name for both your parts of the for loop and have it function as intended. Are they in different scopes? What's going on under the hood that allows something like this to work?

解决方案

What does dis tell us:

Python 3.4.1 (default, May 19 2014, 13:10:29)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from dis import dis
>>> dis("""x = [1,2,3,4,5]
... for x in x:
...     print(x)
... print(x)""")

  1           0 LOAD_CONST               0 (1)
              3 LOAD_CONST               1 (2)
              6 LOAD_CONST               2 (3)
              9 LOAD_CONST               3 (4)
             12 LOAD_CONST               4 (5)
             15 BUILD_LIST               5
             18 STORE_NAME               0 (x)

  2          21 SETUP_LOOP              24 (to 48)
             24 LOAD_NAME                0 (x)
             27 GET_ITER
        >>   28 FOR_ITER                16 (to 47)
             31 STORE_NAME               0 (x)

  3          34 LOAD_NAME                1 (print)
             37 LOAD_NAME                0 (x)
             40 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             43 POP_TOP
             44 JUMP_ABSOLUTE           28
        >>   47 POP_BLOCK

  4     >>   48 LOAD_NAME                1 (print)
             51 LOAD_NAME                0 (x)
             54 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             57 POP_TOP
             58 LOAD_CONST               5 (None)
             61 RETURN_VALUE

The key bits are sections 2 and 3 - we load the value out of x (24 LOAD_NAME 0 (x)) and then we get its iterator (27 GET_ITER) and start iterating over it (28 FOR_ITER). Python never goes back to load the iterator again.

Aside: It wouldn't make any sense to do so, since it already has the iterator, and as Abhijit points out in his answer, Section 7.3 of Python's specification actually requires this behavior).

When the name x gets overwritten to point at each value inside of the list formerly known as x Python doesn't have any problems finding the iterator because it never needs to look at the name x again to finish the iteration protocol.

这篇关于为什么我可以在Python for循环中为迭代器和序列使用相同的名称?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆