본문 바로가기
Programming/Python

[클래스] 클래스 속성과 인스턴스 속성 알아보기

by 용스토리랜드 2023. 3. 13.

[참고] 저자 본인의 공부 및 참고용으로 쓰여진 글인점을 알려드립니다.

# 코딩도장의 내용입니다.

https://dojang.io/mod/page/view.php?id=2378 

 

파이썬 코딩 도장: 35.1 클래스 속성과 인스턴스 속성 알아보기

Unit 35. 클래스 속성과 정적, 클래스 메서드 사용하기 지금까지 간단하게 클래스를 만들고 속성과 메서드를 사용해봤습니다. 이번에는 클래스에 속해 있는 클래스 속성에 대해 알아보겠습니다.

dojang.io

 

>>> james.__dict__
{}
>>> Person.__dict__
mappingproxy({'__module__': '__main__', 'bag': ['책', '열쇠'], 'put_bag': <function Person.put_bag at 0x028A32B8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None})

# 클래스 속성과 인스턴스 속성 알아보기

속성 : 클래스 속성 , 인스턴스 속성 이렇게 두 가지가 있다.

class attribute vs. instance attribute

__init__ 메서드에서 만들었던 속성은 인스턴스 속성 입니다.

 

* 속성(Attribute) : 클래스 내부에 포함돼 있는 메서드나 변수를 의미한다.

# 클래스 속성 사용하기 

클래스 속성은 다음과 같이 클래스에 바로 속성(객체)을 만든다.

class 클래스이름 : 
  속성 = 값

 

class Person : 
  bag = [] 
  
  def put_bag(self, stuff) : 
    self.bag.append(stuff) # instance attribute 을 사용
    
    
james = Person() 
james.put_bag("책")

maria = Person() 
maria.put_bag("열쇠")

print(james.bag) 
print(maria.bag) 

>>> ["책", "열쇠"]
>>> ["책", "열쇠"]

 

 

클래스 속성은 클래스에 속해 있으며 모든 인스턴스에서 공유한다.

put_bag 메서드에서 클래스 속성 bag 에 접근할 때 self 를 사용했다. 사실 self 는 현재 인스턴스를 뜻하므로 클래스 속성을 지칭하기에는 조금 모호하다.

 

그래서 클래스 속성에 접근할 때는 다음과 같이 클래스 이름으로 접근하면 좀 더 코드가 명확해진다. 

class Person : 
  bag = [] 
  
  def put_bag(self, stuff) :
    Person.bag.append(stuff) # 클래스 이름으로 클래스 속성에 접근

Person.bag 이라고 하면 클래스 Person 에 속한 bag 속성이라는 것을 바로 알 수 있다. 마찬가지로 클래스 바깥에서도 다음과 같이 클래스 이름으로 클래스 속성에 접근하면 된다. 

print(Person.bag)

참고 | 속성, 메서드 이름을 찾는 순서

파이썬에서는 속성, 메서드 이름을 찾을 때 인스턴스, 클래스 순으로 찾는다. 인스턴스 속성이 없으면 클래스 속성을 찾게 되므로 james.bag, maria.bag 도 문제 없이 동작한다. 겉보기에는 인스턴스 속성을 사용하는 것 같지만 실제로는 클래스 속성이다. 

 

인스턴스와 클래스에서 __dict__ 속성을 출력해보면 현재 인스턴스와 클래스의 속성을 딕셔너리로 확인할 수 있다.

인스턴스.__dict__

클래스.__dict__

>>> james.__dict__
{}
>>> Person.__dict__
mappingproxy({'__module__': '__main__', 'bag': ['책', '열쇠'], 'put_bag': <function Person.put_bag at 0x028A32B8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None})

 

#인스턴스 속성 사용하기

그럼 가방(attribute) 를 여러 사람이 공유하지 않으려면 어떻게 해야 할까? 그냥 bag 을 인스턴스 속성으로 만들면 된다. 

class Person : 
  def __init__(self) :
    self.bag = [] 
  def put_bag(self, stuff) :
    self.bag.append(stuff)
    
james = Person() 
james.put_bag('책') 

maria = Person()
maria.put_bag('열쇠')
 
print(james.bag)
print(maria.bag)

james.bag maria.bag을 출력해보면 각자 넣은 물건만 출력됩니다. 즉, 인스턴스 속성은 인스턴스별로 독립되어 있으며 서로 영향을 주지 않습니다.

 

<<차이점 정리>>
클래스 속성 : 모든 인스턴스가 attribute 공유. 인스턴스 전체가 사용해야 하는 값을 저장할 때 사용 
인스턴스 속성 : 인스턴스별로 독립되어 있음. 각 인스턴스가 값을 따로 저장해야 할 때 사용

# 비공개 클래스 속성 사용하기

클래스 속성도 비공개 속성을 만들 수 있다. 클래스 속성을 만들 때 __속성 과 같이 __(밑줄 두 개) 로 시작하면 비공개 속성이 된다. 따라서 클래스 안에서만 접근할 수 있고, 클래스 바깥에서는 접근할 수 없다.

class 클래스이름 : 
  __속성 = 값 # 비공개 클래스 속성

 

즉, 클래스에서 공개하고 싶지 않은 속성이 있다면 비공개 클래스 속성을 사용해야 한다. 예를 들어 기사 게임 캐릭터는 아이템을 최대 10개 까지 보유할 수 있다고 하자.

class Knight : 
  __item_limit = 10 # 비공개 클래스 속성 
  
  def print_item_limit(self) : 
    print(Knight.__item_limit) # 클래스 안에서만 접근할 수 있음
    
x = Knight()
x.print_item_limit() # 10

print(Knight.__item_limit) # 클래스 바깥에서는 접근할 수 없음.

실행을 해보면 클래스 Knight의 비공개 클래스 속성 __item_limit는 클래스 안의 print_item_limit 메서드에서만 접근할 수 있고, 클래스 바깥에서 접근하면 에러가 발생합니다. 아이템의 보유 제한이 10개인데, 이 클래스를 사용하는 사람이 마음대로 __item_limit = 1000으로 수정하면 곤란하겠죠?

 

이처럼 비공개 클래스 속성은 클래스 바깥으로 드러내고 싶지 않은 값에 사용합니다.

 

참고 | 클래스와 메서드의 독스트링 사용하기 

함수와 마찬가지로 클래스와 메서드도 독스트링을 사용할 수 있습니다. 다음과 같이 클래스와 메서드를 만들 때 :(콜론) 바로 다음 줄에 """ """(큰따옴표 세 개) 또는 ''' '''(작은따옴표 세 개)로 문자열을 입력하면 됩니다. 그리고 클래스의 독스트링은 클래스.__doc__ 형식으로 사용하고, 메서드의 독스트링은 클래스.메서드.__doc__ 또는 인스턴스.메서드.__doc__ 형식으로 사용합니다

 

class Person:
    '''사람 클래스입니다.'''
    
    def greeting(self):
        '''인사 메서드입니다.'''
        print('Hello')
 
print(Person.__doc__)             # 사람 클래스입니다.
print(Person.greeting.__doc__)    # 인사 메서드입니다.
 
maria = Person()
print(maria.greeting.__doc__)     # 인사 메서드입니다.

 

반응형