All Articles

파이썬 기억 더듬기 (5) - 클래스, 인스턴스

클래스 구성

  • 속성
  • 메소드

‘사람’이 클래스라면 속성은 이름, 나이, 사는 곳 등이고 메소드는 걷다, 뛰다, 먹다 등이다.

클래스와 인스턴스 차이

  • 네임스페이스: 객체를 인스턴스화할 때 객체가 저장된 공간
  • 클래스 변수: 직접 사용 가능, 객체보다 먼저 생성
  • 인스턴스 변수: 객체마다 별도로 존재

클래스 선언하기

class 클래스명:
  함수
  함수
  함수
class UserInfo:
  def __init__(self, name):
    self.name = name

  def print_user_info(self):
    print("Name: ", self.name)

__init__은 클래스를 초기화하는 매직메소드다. 인스턴스를 할당하는 순간 실행된다.

user1 = UserInfo('Park')
user1.print_user_info()

user2 = UserInfo('Jeong')
user1.print_user_info()

print(id(user1))
print(id(user2))
140344096541184
140344096540512

print(user1.__dict__)
print(user2.__dict__)
{'name': 'Park'}
{'name': 'Jeong'}

클래스 메소드와 인스턴스 메소드

func1은 클래스 메소드, self를 인자로 받는 func2는 인스턴스 메소드다. 어떤 차이가 있는지 보자.

class SelfTest:
  def func1():
    print('func1 called')

  def func2(self):
    print('func2 called')
self_test = SelfTest()
SelfTest.func1()
self_test.func2()
func1 called
func2 called

func1과 func2를 호출하는 방식이 조금 다르다. 만약 반대 방식으로 호출한다면 TypeError가 발생한다.

self_test.func1()
TypeError: func1() takes 0 positional arguments but 1 was given

SelfTest.func2()
TypeError: func2() missing 1 required positional argument: 'self'

클래스 메소드는 개별 인스턴스에서 호출할 수 없다. 모든 인스턴스가 이 메소드를 공유한다.

인스턴스 메소드는 인자 없이는 호출할 수 없다. 어떤 인스턴스를 이용해야 하는지 지정하지 않았으므로 에러가 발생한다.

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

class WareHouse:
  # 클래스 변수
  stock_num = 0

  # 창고가 하나 생길 때마다 창고 수 +1
  def __init__(self, name):
    self.name = name
    WareHouse.stock_num += 1

  def __del__(self):
    WareHouse.stock_num -= 1

만든 클래스를 이용해 인스턴스를 할당하자.

user1 = WareHouse('Moon')
user2 = WareHouse('Kim')
user3 = WareHouse('Yang')

할당한 인스턴스를 확인해보자.

print(user1.__dict__)
print(user2.__dict__)
print(user3.__dict__)
{'name': 'Moon'}
{'name': 'Kim'}
{'name': 'Yang'}

같은 방식으로 클래스도 확인해보자.

print(WareHouse.__dict__)
{
  '__module__': '__main__',
  'stock_num': 3,
  '__init__': <function WareHouse.__init__ at 0x7fdbc011c820>,
  '__del__': <function WareHouse.__del__ at 0x7fdbc011c8b0>,
  '__dict__': <attribute '__dict__' of 'WareHouse' objects>,
  '__weakref__': <attribute '__weakref__' of 'WareHouse' objects>,
  '__doc__': None
}

stock_num 키를 보면 값이 3인 것을 확인할 수 있다. 인스턴스 3개를 추가해주었으니 인스턴스 하나를 추가할 때마다 __init__메소드를 타 stock_num 수가 1씩 증가했다.


개별 인스턴스를 조금 더 파보자. 각 인스턴스에서 value를 뽑아낼 수도 있다. __init__ 메소드에서 self.namename 변수로 할당한 점을 이용한다.

print(user1.name)
print(user2.name)
print(user3.name)
Moon
Kim
Yang

혹시 개별 인스턴스에서 창고 수(stock_num)도 뽑아낼 수 있을까?

print(user1.stock_num)
print(user2.stock_num)
print(user3.stock_num)
3
3
3

가능하다. 인스턴스 변수도 아닌데 어떻게 값을 가져올 수 있을까?

위에서 언급했듯 클래스 메소드는 모든 인스턴스가 공유하기 때문에 호출 가능한 것이다. 인스턴스 자신의 네임스페이스에 있으면 그것을 출력하고, 없으면 클래스 네임스페이스로 가서 찾는다. 클래스 네임스페이스에 있으면 리턴하고, 그래도 없으면 에러를 리턴한다.

마지막으로, 인스턴스 하나를 삭제해보자.

del user1

print(user2.stock_num)
print(user3.stock_num)
2
2

__del__ 매직메소드도 잘 타고 있는 것을 확인할 수 있다.