티스토리 뷰

python

list.extend와 list.iadd의 차이

게으른 the lazy 2024. 7. 7. 18:47

 

재밌는 글을 봤다. list.extend와 list.iadd는 표면적으로는 동일해 보인다.

 

 

그런데 함수 내에서 global 변수를 바꾸려고 하면 동작이 달라진다.

 

 

 

 

에러는 global 변수를 바꾸려고 했다는, 흔히 볼 수 있는 에러이다.

문제는 왜 두 개가 다르냐는 것인데,

 

x += something은 객체의 iadd 메서드를 호출하는 것인데, 사실 아래의 코드가 실행된다.

 

x = x.__iadd__(something)

 

여기서 assignment가 문제가 된다.

 

흥미로운 점은, 아래 코드는 문제 없이 잘 돈다.

 

 

여기에는 assignment가 없기 때문이다. x += something은 __iadd__를 호출하고, __iadd__는 self를 반환하므로, x += something은 x의 객체가 바뀌지 않는다. 위 코드에서는 반환값을 x에 재할당하지 않으므로 에러가 발생하지 않는다.

 

extend는 객체의 extend 메서드를 호출하는 것으로, extend 내부에는 assignment가 없다.

 


 

비슷한 맥락의 에러는 튜플 내의 리스트를 변경하려고 할 때에도 볼 수 있다. 아래 내용은 전문가를 위한 파이썬 내용 일부를 가져와서 변경한 것이다.

 

 

 

튜플은 immutable이지만 튜플의 2번째 원소의 id가 바뀐 것이 아니므로 잘 동작한다. 하지만,

 

 

동일 원소에 in-place addition을 하면 에러가 발생한다. 그런데 그 와중에 연산은 또 잘 된다. dis 모듈을 이용하면 바이트코드 레벨에서 연산 과정을 볼 수 있는데,

 

 

10번에서 INPLACE_ADD를 먼저 하고 14번에서 STORE_SUBSCR을 한다. INPLACE_ADD는 문제 없이 잘 되나, STORE에서 문제가 발생한다.

 

어쨌든 in-place addition인 += 또는 __iadd__()는 같은 객체이더라도 무언가 할당하는 것이므로, 튜플 입장에서는 에러를 반환한다.

 

동일 내용은 공식 문서로도 작성되어 있다.


 

 

혹시 잘못된 부분이 있으면 친절한 댓글을...

 

댓글