(Python) class, instance에서의 mutable과 immutable의 관계
파이콘의 https://www.youtube.com/watch?v=su9LkSogAMc 강의를 듣고 정리한 내용입니다
class Student:
hobby_list = [] # 클래스 변수 선언
def __init__(self, name):
self.name = name # 인스턴스 변수 선언 및 초기화
def add_hobby(self, hobby):
self.hobby_list.append(hobby) # 클래스 변수 값 변경
std1 = Student('Kim')
std1.add_hobby('dance')
std1.add_hobby('swim')
print(std1.name, std1.hobby_list) # Kim ['dance', 'swim']
std2 = Student('Son')
print(std2.name, std2.hooby_list) # Son ['dance', 'swim']
Q. kim과 son의 hobby에 대한 list가 똑같이 나오는 이유는 무엇일까?
이유는 hobby_list는 변경가능한 mutable한 자료형이기 때문에 append로 데이터를 추가할 수 있으며 추가된 데이터는 클래스 변수로 선언이 되었기 때문에 나중에 선언된 객체인 std2에도 해당 값이 존재한다. 즉 std1과 std2의 hobby_list는 같은 객체를 가리키고 있는 것이다. 위와 같은 상황이 일어나지 않게 하기 위해서는 공유가 되는 클래스 변수가 아닌 인스턴스 변수 로 넣어주어야 한다
클래스 변수와 데이터 타입
Q. 클래스 변수에 변할 수 없는 데이터 타입을 쓰는 경우에도 새로 변경한 값을 다른 객체가 공유할 수 있는가 ?
답은 공유할 수 없다 이다. 변할 수 없는 데이터 타입(immutable)의 값을 변경하게 되면 새로운 객체가 생성된다. 이 객체는 해당 변수를 가지고 있는 객체 내에서만 접근이 된다. 예를 들어 new_string = std_string + 'abc'
다음과 같은 객체는 new_string에 할당되어지고 이 값은 new_string으로만 접근 할 수 있다.
즉 클래스 변수는 인스턴스화를 하는 시점에 같은 값을 내려받을때 사용한다고 보면된다. 맨 처음 클래스에 대한 인스턴스 a1과 a2가 생성된다면 이 두개의 객체는 동일한 클래스 변수를 내려받게 된다.
class BookReader:
country = 'South Korea'
def __init__(self, name):
self.name = name
def read_book(self):
print(self.name, 'is reading in', self.country)
son = BookReader('son')
hee = BookReader('hee')
son.read_book() # son is reading in South Korea # son과 hee는 똑같은 클래스 변수를 내려받는다
hee.read_book() # hee is reading in South Korea
son.country = 'U.S.A' # hee는 country가 바뀌지 않는다 # son의 새로운 country의 객체가 생성된다. 이제 U.S.A는 son.country로 밖에 접근할 수 없다
son.read_book() # son is reading in U.S.A # son의 country에 대한 객체가 변경되었기 때문에 다음과 같은 값이 나온다
hee.read_book() # hee is reading in South Korea
위의 상황을 다시한번 정리하자면 son은 country를 새롭게 정의를 해주었기 때문에 immutable한 값이 변경되어 객체가 교체되었다.
올바른 클래스 변수 접근 방법
1.내부용 변수 이름은 언더스코어(_) 로 시작한다
2.상수는 대문자로 표기한다
3.클래스 변수 접근은 객체(self)가 아닌 클래스 이름으로 한다
class SKBookReader:
_COUNTRY = 'South Korea'
def __init__(self, name):
self.name = name
def read_book(self):
print(self.name, 'is reading in', SKBookReader._COUNTRY)
jung = SKBookReader('jung')
print(jung.name) # jung
jung.read_book() # jung is reading in South Korea
jung._COUNTRY = 'U.K'
jung.read_book() # # jung is reading in South Korea
위의 코드와 같이 SKBookReader._COUNTRY 로 즉 클래스 네임으로 변수에 접근을 해야만 다른 유저가 클래스 변수값을 바꾸려고 시도해도 바뀌지 않는다. 이를 주의하자 !!!!
기억해야 할 것들
파이썬 변수에 대입되는 객체는 데이터 타입에 따라 변할 수 있거나 변할 수 없는 성질을 갖는다
위 성질에 따라 객체 변경시 서로 다르게 동작하니 주의하여 사용해야 한다
클래스/인스턴스 변수는 서로 다른 유효범위를 갖는다. mutable여부에 따라 예상치 못하게 값이 변경될 수 있다
어떤 변수를 써야 할 지 애매하다면 좁은변수(인스턴스)를 쓰는 것이 안전하다
변수를 내부용으로 정의하고 싶다면 변수 이름을 언더스코어(_)로 시작한다