Development Tip

Python for 루프에서 반복자와 시퀀스에 동일한 이름을 사용할 수있는 이유는 무엇입니까?

yourdevel 2020. 10. 14. 21:22
반응형

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에 할당 된 마지막 값이 될 것입니다 인쇄 된 마지막 값이 이해하는 나에게 의미가 for루프가 의도 한대로 작동합니다. 다른 범위에 있습니까? 이와 같은 작업을 가능하게하는 내부에서 무슨 일이 일어나고 있습니까?


dis우리에게 무엇을 합니까 :

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

핵심 비트는 섹션 2와 3입니다. x( 24 LOAD_NAME 0 (x)) 에서 값을로드 한 다음 반복자 ( 27 GET_ITER)를 가져와 반복을 시작합니다 ( 28 FOR_ITER). 파이썬 은 반복자를 다시로드하기 위해 돌아 가지 않습니다 .

제외 : 그것은 이미 반복자를 가지고 있기 때문에, 그렇게 할 말이없는 것이고, 같은 Abhijit는 그의 대답에 지적 , 파이썬의 사양의 섹션 7.3 ) 실제로이 동작을 필요로한다.

x이전에 xPython으로 알려진 목록 내의 각 값을 가리 키 도록 이름 을 덮어 쓰면 x반복 프로토콜을 완료하기 위해 이름을 다시 볼 필요가 없기 때문에 반복자를 찾는 데 문제가 없습니다 .


예제 코드를 핵심 참조로 사용

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

섹션 7.3 을 참조하시기 바랍니다 . 매뉴얼 의 for 문

발췌 1

표현식 목록은 한 번 평가됩니다. 반복 가능한 객체를 생성해야합니다. expression_list의 결과에 대해 반복기가 생성됩니다.

그것은 무엇을 의미하는 것은 변수이다 x오브젝트의 기호 이름입니다 list: [1,2,3,4,5]반복 가능 객체로 평가된다. 변수, 기호 참조가 그 충성도를 변경하더라도 expression-list 가 다시 평가되지 않으므로 이미 평가 및 생성 된 반복 가능한 객체에는 영향을 미치지 않습니다.

노트

  • Python의 모든 것은 객체이며 식별자, 속성 및 메서드가 있습니다.
  • 변수는 지정된 인스턴스에서 단 하나의 객체에 대한 참조 인 기호 이름입니다.
  • 런타임의 변수는 충성도를 변경할 수 있습니다. 즉, 다른 객체를 참조 할 수 있습니다.

발췌 2

그런 다음 스위트는 인덱스 오름차순으로 반복자가 제공하는 각 항목에 대해 한 번씩 실행됩니다.

여기서 스위트는 표현식 목록이 아닌 반복자를 나타냅니다. 따라서 각 반복에 대해 원래 표현식 목록을 참조하는 대신 다음 항목을 생성하기 위해 반복기가 실행됩니다.


생각해 보면 이런 식으로 작동하는 것이 필요합니다. for루프 시퀀스에 대한 표현식은 다음과 같을 수 있습니다.

binaryfile = open("file", "rb")
for byte in binaryfile.read(5):
    ...

루프를 통과 할 때마다 시퀀스를 쿼리 할 수 ​​없거나 여기서는 다음 5 바이트 배치에서 두 번째로 읽습니다 . 당연히 파이썬은 루프가 시작되기 전에 어떤 식 으로든 표현식의 결과를 비공개로 저장해야합니다.


다른 범위에 있습니까?

No. To confirm this you could keep a reference to the original scope dictionary (locals()) and notice that you are in fact using the same variables inside the loop:

x = [1,2,3,4,5]
loc = locals()
for x in x:
    print locals() is loc  # True
    print loc["x"]  # 1
    break

What's going on under the hood that allows something like this to work?

Sean Vieira showed exactly what is going on under the hood, but to describe it in more readable python code, your for loop is essentially equivalent to this while loop:

it = iter(x)
while True:
    try:
        x = it.next()
    except StopIteration:
        break
    print x

This is different from the traditional indexing approach to iteration you would see in older versions of Java, for example:

for (int index = 0; index < x.length; index++) {
    x = x[index];
    ...
 }

This approach would fail when the item variable and the sequence variable are the same, because the sequence x would no longer be available to look up the next index after the first time x was reassigned to the first item.

With the former approach, however, the first line (it = iter(x)) requests an iterator object which is what is actually responsible for providing the next item from then on. The sequence that x originally pointed to no longer needs to be accessed directly.


It's the difference between a variable (x) and the object it points to (the list). When the for loop starts, Python grabs an internal reference to the object pointed to by x. It uses the object and not what x happens to reference at any given time.

If you reassign x, the for loop doesn't change. If x points to a mutable object (e.g., a list) and you change that object (e.g., delete an element) results can be unpredictable.


Basically, the for loop takes in the list x, and then, storing that as a temporary variable, reassigns a x to each value in that temporary variable. Thus, x is now the last value in the list.

>>> x = [1, 2, 3]
>>> [x for x in x]
[1, 2, 3]
>>> x
3
>>> 

Just like in this:

>>> def foo(bar):
...     return bar
... 
>>> x = [1, 2, 3]
>>> for x in foo(x):
...     print x
... 
1
2
3
>>> 

In this example, x is stored in foo() as bar, so although x is being reassigned, it still exist(ed) in foo() so that we could use it to trigger our for loop.


x no longer refers to the original x list, and so there's no confusion. Basically, python remembers it's iterating over the original x list, but as soon as you start assigning the iteration value (0,1,2, etc) to the name x, it no longer refers to the original x list. The name gets reassigned to the iteration value.

In [1]: x = range(5)

In [2]: x
Out[2]: [0, 1, 2, 3, 4]

In [3]: id(x)
Out[3]: 4371091680

In [4]: for x in x:
   ...:     print id(x), x
   ...:     
140470424504688 0
140470424504664 1
140470424504640 2
140470424504616 3
140470424504592 4

In [5]: id(x)
Out[5]: 140470424504592

참고URL : https://stackoverflow.com/questions/24689967/why-can-i-use-the-same-name-for-iterator-and-sequence-in-a-python-for-loop

반응형