본문 바로가기

기타

Python instance variable, class variable 관련 내용

동아리에서 Python 강의하다가 클래스 변수 부분에서 코드 시연을 할 때 절었다.

아래와 같은 코드를 작성했다고 하자.

class Test:
    cls = 1
    def __init__(self):
        pass
    def print_cls(self):
        print(self.cls)
 
 test_a, test_b, = Test(), Test()
 test_a.cls = 2
 print(test_a == test_b)

Python에서의 출력은 False다.

public class test {
    public static class TestClass{
        public static int cls = 1;
    }
    public static void main(String[] args){
        TestClass test_a = new TestClass();
        TestClass test_b = new TestClass();
    
        test_a.cls = 2;
        System.out.println(test_a.cls);
        System.out.println(test_b.cls);
    }
}

Java에서는 test_a.cls와 test_b.cls의 값이 같다.

똑같이 instance의 class variable을 수정했는데도 Python은 수정이 안되고 Java는 수정이 된다. 아래의 코드를 통해 각 변수의 메모리 주소를 출력하면 다음과 같다.

print(hex(id(Test.cls)), hex(id(test_a.cls)), hex(id(test_b.cls)))
# OUTPUT: 0x1d26fad00f0 0x1d26fad0110 0x1d26fad00f0

그러니까 Test.cls와 test_b.cls의 주소는 그대로인데 test_a.cls의 값이 바뀌면서 변수의 주소도 같이 바뀌었다. 이거 mutable object, immutable object의 개념을 알고 있다면 거기서 생긴 문젠가 떠오를 것이다. 그래서 class variable을 list로 바꾸고 index로 접근했다.

class Test:
    cls = [0]
    def __init__(self):
        pass
    def print_cls(self):
        print(self.cls)

test_a, test_b, = Test(), Test()
test_a.cls[0] = 2
print(test_a.cls == test_b.cls)
print(hex(id(Test.cls)), hex(id(test_a.cls)), hex(id(test_b.cls)))

# OUTPUT: True
# OUTPUT: 0x1e5a91c4880 0x1e5a91c4880 0x1e5a91c4880

그렇다. class variable이 mutable object면 메모리를 새로 할당하지 않은 채 내부의 값만 수정하기 때문에 Java 코드와 동일한 결과가 도출된다. 하지만 immutable object면 새로운 메모리에 변수를 생성하기 때문에 그 객체의 클래스 변수만 인스턴스 변수화 된다. (다만 이 부분은 내부적으로 Python이 어떻게 인식하고 있는지 확인할 길이 없어보인다.)

그렇다면 class_name.class_variable 형태로 수정하면 어떨까?

class Test:
    cls = 1
    def __init__(self):
        pass
    def print_cls(self):
        print(self.cls)

test_a, test_b, = Test(), Test()
Test.cls = 2
print(test_a.cls, test_b.cls)
print(hex(id(Test.cls)), hex(id(test_a.cls)), hex(id(test_b.cls)))

# OUTPUT: 2 2
# OUTPUT: 0x2379fc80110 0x2379fc80110 0x2379fc80110

가장 안전한 방법은 인스턴스가 아닌 클래스 단에서 클래스 변수를 조작하는 것인 것 같다.