WeniVooks

검색

견고한 파이썬

클래스 변수와 인스턴스 변수

1. 클래스 변수

클래스 변수는 클래스 바로 하위에 자리하고 있는 변수들입니다. 이 클래스 변수는 아래의 예시와 같이 클래스 이름, 인스턴스 이름을 통해서 접근할 수 있습니다.

class Car: # 클래스 변수의 위치 max_speed = 300 max_people = 5 modelx = Car() print(Car.max_speed) print(modelx.max_speed)

이 클래스 변수는 해당 클래스를 통해 만들어진 모든 인스턴스 객체들이 공유하는 변수 값입니다. 반면 인스턴스 변수는 각 인스턴스 객체가 고유하게 가지고 있는 변수 값입니다. 이 클래스 변수는 클래스 이름을 통해 접근할 수 있습니다. 또한 인스턴스 객체를 통해서도 접근할 수 있습니다.

class Car: # 클래스 변수의 위치 max_speed = 300 max_people = 5 modelx = Car() modely = Car() modely.max_speed = 500 print(Car.max_speed) print(modelx.max_speed) print(modely.max_speed)

위와 같이 작성하면 modely의 max_speed는 500이 됩니다. 모든 변수가 공유하는 변수라고 하였으니 modelx의 값도 바뀌어야 할 것 같지만 modely.max_speed 값을 조정하는 것은 modely의 인스턴스 변수의 값을 조정하는 것과 같습니다.

아래와 같이 바꾸면 modelx의 값도 바뀌게 됩니다.

class Car: # 클래스 변수의 위치 max_speed = 300 max_people = 5 modelx = Car() modely = Car() Car.max_speed = 500 print(Car.max_speed) print(modelx.max_speed) print(modely.max_speed)

모든 값이 수정된 것을 확인할 수 있습니다. 이는 실제로 두 개의 인스턴스가 max_speed, max_people 각각의 메모리 영역이 아니라 하나의 메모리 영역을 공유하고 있다는 것을 말해줍니다.

다음 예제는 조금 어렵습니다. 헷갈리지 않도록 주의해주세요. 아래 코드를 주석을 풀고, Car의 speed 값을 변경하는 코드는 주석 처리하겠습니다.

class Car: speed = 300 def change_speed(self, speed): self.speed = speed modelx = Car() modely = Car() modelx.change_speed(500) modely.change_speed(250) print(f'modelx.speed: {modelx.speed}') print(f'modely.speed: {modely.speed}')

출력 값이 어떻게 되었을지 예상해보세요. 분명 클래스 변수를 수정한 것 같은데 두 수의 스피드가 공유되고 있지 않습니다. 뒤에 수정된 변수가 반영되어서 둘 다 250을 출력하는 것이 합당해 보입니다.

def change_speed(self, speed):
    self.speed = speed
def change_speed(self, speed):
    self.speed = speed

여기서 self.speed는 상위에 있는 speed를 조작하지 않습니다. 이는 인스턴스 변수가 생성된 것 뿐입니다. 따라서 아래처럼 출력이 됩니다.

# 출력
modelx.speed: 500
modely.speed: 250
# 출력
modelx.speed: 500
modely.speed: 250

그렇다면 300은 어떻게 된 것인지 확인해보도록 하겠습니다. 아래 코드를 실행해보세요.

class Car: speed = 300 def change_speed(self, speed): self.speed = speed modelx = Car() modely = Car() modelx.change_speed(500) modely.change_speed(250) print(f'modelx.speed: {modelx.speed}') print(f'modely.speed: {modely.speed}') Car.speed

300은 그대로 클래스 변수에 남겨져 있습니다. 이는 마치 아래 코드와 같습니다.

speed = 300 # 전역변수 speed 300 def change_speed(value): speed = value # 지역변수 speed change_speed(100) speed # 출력: 300

이렇듯 헷갈리는 예제를 준비한 것은 각각의 메모리 영역을 명확하게 이해할 수 있어야 견고한 코드를 짤 수 있기 때문입니다. 클래스의 메모리 영역이 어디인지, 인스턴스의 메모리 영역이 어디인지 구분할 필요가 있습니다.

다음 예제는 위 예제와 비슷하게 보이지만 실제로는 클래스 변수를 수정하는 예제입니다.

class Car: kinds = [] speed = 300 def add_kinds(self, name): self.kinds.append(name) def change_speed(self, speed): self.speed = speed modelx = Car() modely = Car() modelx.add_kinds('modelx') modely.add_kinds('modely') print(modelx.kinds) print(modely.kinds)

앞 클래스에서kinds 배열의 경우에는 add_kinds 메서드 안에서 각 인스턴스 객체가 해당 배열의 주소를 참조하고 있어, 그 배열의 주소에 접근하여 조작했기 때문에 클래스 변수를 직접 수정한 것처럼 동작을 하게 된 것입니다. 반면에 speed의 경우에는 change_speed 메서드 안에서 인스턴스 변수를 생성하여 값을 가지게 된 것입니다. 이는 함수에서 리스트가 전달되고 함수 내부에서 리스트를 조작하면 원본 리스트도 변경되는 것과 같은 원리입니다.

def change_list(l): l.append(100) l = [1, 2, 3] change_list(l) print(l) # 출력: [1, 2, 3, 100]

다만 이렇게 수정하게 하였을 경우에 인스턴스 변수를 수정하는 것인지, 클래스 변수를 선언하는 것인지 헷갈릴 수 있어 아래와 같이 수정하는 것이 좋습니다. 추후에 배울 @classmethod 데코레이터를 사용하면 클래스 변수를 수정하는 것임을 명확하게 할 수 있습니다.

class Car: kinds = [] speed = 300 def add_kinds(self, name): Car.kinds.append(name) modelx = Car() modely = Car() modelx.add_kinds('modelx') modely.add_kinds('modely') print(modelx.kinds) print(modely.kinds)

2. 인스턴스 변수

인스턴스 변수는 클래스 변수와 다르게 각 인스턴스 객체가 가지고 있는 변수입니다. 클래스 변수는 클래스가 메모리에 로드될 때 생성되지만, 인스턴스 변수는 인스턴스 객체가 생성될 때 생성됩니다.

인스턴스 변수는 self가 위치한 어디서나 선언이 가능하지만 보통 __init__ 메서드 안에서 선언됩니다. __init__ 메서드는 다른 프로그래밍 언어에서 생성자(constructor)라 불립니다. 언더바가 2개 앞뒤로 있는 메서드는 매직 메서드, 던더 함수라고 불립니다. 우리는 있는 그대로 이닛(__init__) 매직 메서드라고 말하도록 하겠습니다. 이 메서드는 인스턴스 객체를 생성할 때 자동으로 실행됩니다.

class Car: max_speed = 300 def __init__(self, name): # self는 인스턴스 고유의 영역 self.name = name def start(self, speed): # self는 인스턴스 고유의 영역 self.speed = speed return f'{self.name}차가 {self.speed}의 속력으로 움직이고 있습니다.' modelx = Car('Weniv Model X') print(modelx.name) print(modelx.start(100))

self가 있는 곳에서 선언된 변수들은 인스턴스의 영역으로 간주되어 dot으로 호출할 수 있습니다. 이 변수는 다른 인스턴스와 메모리 영역을 공유하지 않습니다. 또한 이 값은 아래와 같이 추가 또는 변경이 될 수 있습니다.

class Car: max_speed = 300 def __init__(self, name): # self는 자신만의 영역 self.name = name def start(self, speed): # self는 자신만의 영역 self.speed = speed return f'{self.name}차가 {self.speed}의 속력으로 움직이고 있습니다.' modelx = Car('Weniv Model X') modelx.name = 'ModelY' modelx.welcome = 'hello world' print(modelx.name, modelx.welcome) # 출력: ModelY hello world

3. 다른 자료형의 인스턴스 변수 변경

우리는 hello의 type을 출력해 봄으로써 함수도 class라는 것을 알 수 있습니다. 그렇다면 함수에 인스턴스 변수를 생성할 수 있는지 확인해보도록 하겠습니다.

def hello(): print('hello world') print(type(hello)) # 출력: <class 'function'>

인스턴스 변수를 넣어보도록 하겠습니다.

hello.hi = 'hi, world'
hello.hi # 출력: hi, world
hello.hi = 'hi, world'
hello.hi # 출력: hi, world

다만 기본으로 내장되어 있는 자료형은 대부분 이를 허락하고 있지 않습니다.

s = 'hello' s.hi = 'hi, world' s.hi # error s = [10, 20, 30] s.hi = 'hi, world' # s.hi # error s = {'one':1} s.hi = 'hi, world' # s.hi # error

4. 클래스, 인스턴스 변수 요약

중요한 내용이니 요약하고 가도록 하겠습니다.

4.1 클래스 변수
  • 정의: 클래스 변수는 클래스 정의 내에 선언되며, 클래스의 모든 인스턴스 간에 공유됩니다. 클래스 변수는 클래스가 메모리에 로드될 때 생성됩니다.
  • 용도: 클래스 변수는 해당 클래스의 모든 인스턴스에서 공통적으로 사용되는 값을 저장하는 데 사용됩니다. 예를 들어, 모든 Car 객체에 공통적으로 적용되는 기본 속도 설정과 같은 경우에 사용됩니다.
  • 접근 방법: 클래스 이름을 통해 접근하거나 self를 통해 인스턴스를 통해서도 접근할 수 있습니다. Car.max_speed와 같은 형태로 사용할 수 있습니다.
  • 특징: 클래스 변수의 값을 변경하면, 해당 클래스의 모든 인스턴스에 대해 변경사항이 적용됩니다.
4.2 인스턴스 변수
  • 정의: 인스턴스 변수는 클래스의 각 인스턴스(객체)에 속하는 변수입니다. 이 변수들은 각 인스턴스마다 별도로 존재하며, 인스턴스 생성 시에 만들어집니다.
  • 용도: 인스턴스 변수는 개별 객체의 상태를 저장하는 데 사용됩니다. 예를 들어, 여러 Car 객체가 있을 때 각 Car의 속도나 색상 같은 고유한 속성을 인스턴스 변수로 저장할 수 있습니다.
  • 접근 방법: self 키워드를 사용하여 인스턴스 내에서 이 변수에 접근하고 수정합니다. self.max_speed = 200와 같은 형태로 사용할 수 있습니다.
  • 특징: 각 인스턴스의 변수는 서로 독립적이므로, 한 인스턴스에서 변수의 값을 변경해도 다른 인스턴스의 동일한 변수에는 영향을 주지 않습니다.
{"packages":["numpy","pandas","matplotlib","lxml"]}
10.2 클래스를 왜 써야 하는가?10.4 매직 메서드