이것은 더 개념적인 질문입니다. 최근에 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
). Python 은 반복자를 다시로드하기 위해 다시 돌아 가지 않습니다. .
제외 : 그것은 이미 반복자를 가지고 있기 때문에, 그렇게 할 말이없는 것이고, 같은 Abhijit는 그의 대답에 지적 , 파이썬의 사양의 섹션 7.3 ) 실제로이 동작을 필요로한다.
x
이전에 x
Python으로 알려진 목록 내의 각 값을 가리 키 도록 이름 을 덮어 쓰면 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 바이트 배치에서 두 번째로 읽습니다 . 당연히 파이썬은 루프가 시작되기 전에 어떤 식 으로든 표현식의 결과를 비공개로 저장해야합니다.
다른 범위에 있습니까?
아니오.이를 확인하기 위해 원래 범위 사전 ( locals () )에 대한 참조를 유지하고 실제로 루프 내에서 동일한 변수를 사용하고 있음을 알 수 있습니다.
x = [1,2,3,4,5]
loc = locals()
for x in x:
print locals() is loc # True
print loc["x"] # 1
break
이와 같은 작업을 가능하게하는 내부에서 무슨 일이 일어나고 있습니까?
Sean Vieira 는 내부에서 무슨 일이 일어나고 있는지 정확히 보여 주었지만 더 읽기 쉬운 파이썬 코드로 설명하기 위해 for
루프는 본질적으로 다음 while
루프 와 동일합니다 .
it = iter(x)
while True:
try:
x = it.next()
except StopIteration:
break
print x
이것은 이전 버전의 Java에서 볼 수있는 반복에 대한 기존의 인덱싱 접근 방식과 다릅니다. 예를 들면 다음과 같습니다.
for (int index = 0; index < x.length; index++) {
x = x[index];
...
}
이 접근 방식은 항목 변수와 시퀀스 변수가 동일한 경우 실패 합니다. 첫 번째 항목에 처음으로 다시 할당 된 x
후 시퀀스 가 더 이상 다음 인덱스를 조회하는 데 사용할 수 없기 때문 x
입니다.
그러나 전자의 접근 방식을 사용하면 첫 번째 줄 ( it = iter(x)
) 은 그때부터 다음 항목을 제공 할 실제로 책임이 있는 반복기 객체 를 요청합니다 . x
원래 가리키는 시퀀스는 더 이상 직접 액세스 할 필요가 없습니다.
답변
변수 (x)와 그것이 가리키는 객체 (목록)의 차이입니다. for 루프가 시작되면 Python은 x가 가리키는 객체에 대한 내부 참조를 가져옵니다. x가 주어진 시간에 참조하는 것이 아니라 객체를 사용합니다.
x를 재 할당해도 for 루프는 변경되지 않습니다. x가 변경 가능한 객체 (예 : 목록)를 가리키고 해당 객체를 변경 (예 : 요소 삭제)하면 결과를 예측할 수 없습니다.
답변
기본적으로 for 루프는 list를 가져 와서 x
임시 변수로 저장 한 다음 해당 임시 변수의 각 값에 a 를 다시 할당 x
합니다. 따라서 x
이제는 목록의 마지막 값입니다.
>>> x = [1, 2, 3]
>>> [x for x in x]
[1, 2, 3]
>>> x
3
>>>
다음과 같이 :
>>> def foo(bar):
... return bar
...
>>> x = [1, 2, 3]
>>> for x in foo(x):
... print x
...
1
2
3
>>>
이 예에서, x
저장된다 foo()
같은 bar
정도로되지만, x
재 할당되고, 그것은 여전히 (ED)에 존재하는 foo()
우리가 우리의 트리거를 사용할 수 for
루프.
답변
x
더 이상 원래 x
목록을 참조 하지 않으므로 혼동이 없습니다. 기본적으로 Python은 원래 x
목록을 반복하고 있음을 기억 하지만 반복 값 (0,1,2 등)을 name에 할당하기 시작 x
하면 더 이상 원래 x
목록을 참조하지 않습니다 . 이름이 반복 값에 다시 할당됩니다.
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
답변
