불변 객체는 생각보다 중요합니다. 예를 들자면, 해시에서 키를 넣을 때, 변할 수 있는 객체면 곤란해 질 수 있습니다. 왜냐하면 객체의 내용이 변하면 hash값이 변하기 때문입니다. 하지만, hash에서 탐색하기 시작하는 위치는 안 바뀌기 때문에 (재해싱을 하지 않는 이상) 이상하게 동작하게 됩니다.

 

 python에서는 immutable을 흉내낼 수 있는 것이 있는데요. dataclasses의 frozen을 True로 설정하면 가능합니다. 간단하게 알아보겠습니다.

 


 3.7부터 추가된 dataclass를 이용해서, immutable을 흉내낼 수 있다고 하였습니다. 잠깐. immutable의 대표적인 것은 tuple이 있습니다. 반면, mutable은 list가 있습니다. list는 append 등으로 원소를 뒤에 추가할 수 있기 때문입니다. 위 문서에서 frozen이 참일 때 어떤 일이 일어나는지를 설명해 주고 있어요. instance가 생성된 후에 field에 값을 대입할 수 없다.

 

 불변 흉내를 낼 수 있다는 소리입니다. 예제를 보겠습니다.

 

 class Obj가 있는데요. frozen이 True로 되어 있어요. 고로, x와 y는 생성이 되고 난 후에는 아예 초기화를 할 수 없습니다. 어떻게 초기화를 시킬까요?

 

 o1 = Obj(x=3, y=3) 요래 넘겨줍니다. 그러면 생성이 되는 단계에서 x에 3을 집어넣고, y에 3을 집어넣습니다. 그리고 끝납니다. 그 이후에는 대입를 할 수 없습니다.

 

 실행 결과는 요래 나오게 됩니다.

 

 12번째 줄에 o1.x = 3이라고 입력했더니, 에러가 뜹니다. 왜? Obj object의 x가 읽기 전용이기 때문입니다. o1.x = 3를 실행했을 때에는, 이미 객체 o1이 생성 되고 난 후였습니다. 그렇기 때문에, o1.x에 assign을 하는 것 자체가 되지 않습니다.

 

 그러면, __setattr__ 등으로 할 수 있지 않을까요? __setattr__은 속성에 값을 집어넣습니다.

 

 실행을 시켜 보니, FrozenInstanceError가 나오게 됩니다. 이미 만들어진 객체의 필드에 다른 값을 assign 할 수 없다는 의미입니다.

 


 조심해야 할 것은, 생성이 된 객체의 필드에 assign이 안 된다는 것입니다. 이 말은, field가 mutable인 경우에, field의 내부 값이 변경될 수도 있다는 것입니다.

 

 z: list라고 되어 있습니다. 리스트는 아시다 시피 불변 객체가 아닙니다. o1을 생성하는 과정에서 z가 초기화 되었습니다. list 객체로요. 그런데, assign만 안 될 뿐이지, 생성된 객체에 append를 해서 상태를 변경시킬 수 있어요. o1.z.append("3"), o1.z.append("4")를 수행하는데요. o1.z가 불변 객체가 아니기 때문에, o1 안에 들어있는 list에 3과 4가 추가되게 됩니다.

 

 

 실행 결과는 위와 같습니다.