2014-01-10 5 views
18
In [55]: a = 5 

In [56]: b = 6 

In [57]: (a, b) = (b, a) 

In [58]: a 
Out[58]: 6 

In [59]: b 
Out[59]: 5 

a와 b의 값을 내부적으로 교환하는 방법은 무엇입니까? 그것은 확실히 임시 변수를 사용하지 않습니다.파이썬 튜플 (a, b) = (b, a)의 멤버를 내부적으로 교환하는 방법은 무엇입니까?

+0

'확실히 임시 변수를 사용하지 않습니까? '이것은 이상한 질문입니다. 그것은 당신이 그것을 알고있는 것처럼 들린다. – RedX

+1

['dis'] (http://docs.python.org/3/library/dis.html)를 사용하여 코드 해체를 확인하십시오. Spoliers : 바이트 코드 명령어 ['ROT_TWO'] (http://docs.python.org/2/library/dis.html#opcode-ROT_TWO)가 사용됩니다. – Kevin

+0

@RedX : 내가 알았다면 나는이 질문을하지 않았을 것이다. 임시 변수를 사용하는 것은 스와핑에 대한 간단한 접근법입니다. – praveen

답변

54

파이썬은 오른쪽 수식과 왼쪽 수식을 구분합니다. 먼저 오른쪽이 계산되고 스택에 결과가 저장되고 왼쪽에있는 이름은 값을 가진 opcode를 사용하여 할당됩니다.에서 다시 스택이됩니다.

2-3 항목 튜플 할당은

가 파이썬 단지 직접 스택 사용 (스택에 변수의 값을 푸시) 두 LOAD_FAST opcodes

>>> import dis 
>>> def foo(a, b): 
...  a, b = b, a 
... 
>>> dis.dis(foo) 
    2   0 LOAD_FAST    1 (b) 
       3 LOAD_FAST    0 (a) 
       6 ROT_TWO    
       7 STORE_FAST    0 (a) 
      10 STORE_FAST    1 (b) 
      13 LOAD_CONST    0 (None) 
      16 RETURN_VALUE   

를, 스택의 상단 [a, b] 보유 . ROT_TWO opcode은 스택의 상단 두 위치를 바꿔서 이제 스택의 상단에 [b, a]이 있습니다. 두 STORE_FAST opcodes은 두 값을 가져 와서 할당 왼쪽에있는 이름에 저장합니다. 첫 번째 STORE_FAST은 스택의 최상위 값을 가져와 a에 넣고 다음 번 다시 팝하여 b에 값을 저장합니다. Python은 왼쪽의 대상 목록에있는 할당이 왼쪽에서 오른쪽으로 수행되도록 보장하기 때문에 회전이 필요합니다.

3 자 지정의 경우 ROT_THREE 다음에 ROT_TWO이 실행되어 스택의 상위 3 개 항목을 뒤집습니다. 더 이상 왼손 측 할당에 대한

는 명시 적 튜플이 내장되어 있습니다 :

[d, c, b, a]와 스택 밀어 다시 스택에서 역순으로 ( BUILD_TUPLE 팝을 튜플을 구축하는 데 사용됩니다 여기에
>>> def bar(a, b, c, d): 
...  d, c, b, a = a, b, c, d 
... 
>>> dis.dis(bar) 
    2   0 LOAD_FAST    0 (a) 
       3 LOAD_FAST    1 (b) 
       6 LOAD_FAST    2 (c) 
       9 LOAD_FAST    3 (d) 
      12 BUILD_TUPLE    4 
      15 UNPACK_SEQUENCE   4 
      18 STORE_FAST    3 (d) 
      21 STORE_FAST    2 (c) 
      24 STORE_FAST    1 (b) 
      27 STORE_FAST    0 (a) 
      30 LOAD_CONST    0 (None) 
      33 RETURN_VALUE   

결과 집합을 스택에 놓은 다음) UNPACK_SEQUENCE은 스택에서 다시 터플을 팝하고 STORE_FAST 작업을 위해 다시 터플에서 모든 요소를 ​​다시 스택으로 푸시합니다.

후자는 낭비 작업처럼 보일 수 있지만, 파이썬 인터프리터는 어떠한 가정도하지 않으며 UNPACK_SEQUENCE를 사용하므로 할당의 오른쪽이 완전히 다른 무언가, 아마도 튜플을 생성하는 함수를 호출 할 수있다 항상 opcode. 두 및 세 이름 지정 작업의 경우에도 마찬가지입니다. but a later (peephole) optimization step은 효율을 위해 위의 ROT_TWOROT_THREE opcode로 2 또는 3 인수를 사용하여 BUILD_TUPLE/UNPACK_SEQUENCE 조합을 바꿉니다.

+1

+1 ** 왼쪽에있는 대상 목록의 지정이 왼쪽에서 오른쪽으로 이루어 지도록 Python에서 보장하기 때문에 회전이 필요합니다. **. 난 몰랐어. –