본문 바로가기
Computer Science/Python

+= 복합 할당 문제

by Bloofer 2022. 11. 12.

파이썬 튜플은 Immutable Sequence이다. 그러나, 튜플에는 복합 타입의 원소들을 다룰 수 있고, 이에 대해 += 연산자를 사용하였을 때 이상한 일이 발생한다.

 

아래와 같은 (int, int, list[int]) 타입의 튜플에 += 연산자를 사용하면 무슨 일이 발생하겠는가?

 

>> t = (1, 2, [3, 4])
>> t[2] += [5, 6]

 

  1. t가 (1, 2, [3, 4, 5, 6])가 된다.
  2. 튜플 객체는 item assignment 연산을 지원하지 않는다는 에러메세지와 함께 타입에러 발생

 

 

놀랍게도 두가지 일이 동시에 일어난다.

 

>> t = (1, 2, [3, 4])
>> t[2] += [5, 6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>> t
(1, 2, [3, 4, 5, 6])

 

 

 

왜 이런 결과가 발생했을까?

s[a] += b 표현식에 대해 파이썬 바이트 코드를 뜯어보면 그 원인을 파악할 수 있다.

 

>> import dis
>> dis.dis('s[a] += b')
  1           0 LOAD_NAME                0 (s)
              2 LOAD_NAME                1 (a)
              4 DUP_TOP_TWO
              6 BINARY_SUBSCR
              8 LOAD_NAME                2 (b)
             10 INPLACE_ADD
             12 ROT_THREE
             14 STORE_SUBSCR
             16 LOAD_CONST               0 (None)
             18 RETURN_VALUE

 

2 BINARY_SUBSCR: s[a] 값을 스택의 꼭대기(TOS)에 놓는다.

10 INPLACE_ADD: TOS += b를 수행한다. TOS가 여기서 Mutable Sequence를 가리키면 이 연산은 성공한다.

14 STORE_SUBSCR: TOS를 s[a]에 할당한다. s가 Immutable Sequence를 가리키면 이 연산은 실패한다.

 

 

물론, 이 경우는 흔하지 않은 케이스지만 여기서 얻을 수 있는 교훈은 다음과 같다.

 

  • 튜플에 가변 배열을 넣는 일 따위는 애초에 하지 말아야 한다는 것
  • 복합할당은 atomic한 연산이 아니다. (연산이 수행한 후 TOS의 할당단계에서 일어나는 예외케이스를 보면)

 

원문: https://www.fluentpython.com/