본문 바로가기

진리는어디에/Python

[Python] 클래스(class) #5 special method

목차

  1. 파이썬 클래스 소개
  2. instance vs static
  3. dict vs slots
  4. property의 활용
  5. >> special method
  6. callable object
  7. 클래스 데코레이터(class decorator)
  8. 상속
  9. 추상 클래스와 추상 메소드

스페셜 메소드(special method)란?

  • 스페셜 메소드는 특정 상황에서 자동으로 호출 되는 메소드(이름이 약속되어 있는 메소드)들을 일컫는 말이다.
  • 스페셜 메소드는 __xx__() 형태, 앞에 언더바 두 개, 뒤에 언더바 두개 형태를 가진다.
  • 스페셜 메소드는 파이썬 표준 타입과 유사하게 동작하는 클래스를 설계하기 위해서 반드시 필요하다.
  • 약 100여개가 넘는 스페셜 메소드가 있다. 

스페셜 메소드의 사용 예

스페셜 메소드는 특정 상황에서 자동 호출 되는 미리 약속되어 있는 메소드다. 아래 예제의 생성자도 __init__이라는 이름을 가진 스페셜 메소드 중에 하나다. 객체가 생성 될 때 호출 되는 __init__()뿐만아니라 객체가 파괴 될 때 호출 되는 __del__() 역시 스페셜 메소드다. 이렇게 다양한 상황에서 호출 되는 스페셜 메소드는 약 100여개가 넘는다.

100여개가 넘는  모든 스페셜 메소드들을 이 포스트에서 전부 다루기는 지면상이나 시간상 불가능하므로 자주 사용되는 스페셜 메소드의 예 몇가지를 살펴 보도록 하겠다. 나머지는 [여기] 파이썬 공식문서를 참고 하도록 하자.

len()

len() 함수는 문자열의 길이 또는 시퀀스의 요소 개수등을 조사하기 위해 사용되는 표준 함수다. 아래 예제는 Sentence라는 클래스의 words 필드에 저장되어 있는 문자열들의 개수를 조사하고자 하지만 실행 시켜보면 Sentence 객체는 len() 함수가 없다는 오류를 발생 시킬 뿐이다.

class Sentence :
    def __init__(self, s) :
        self.words = s.split()

s = Sentence('Sometimes bad things happen to good people')

print(len('hello'))
print(len([1, 2, 3, 4, 5]))

print(s.words) # ['Sometimes', 'bad', 'things', 'happen', 'to', 'good', 'people']
print(len(s))  # TypeError: object of type 'Sentence' has no len()

사용자가 정의한 클래스가 len() 표준함수를 지원하기 위해서는 약속된 "__len__()" 스페셜 메소드를 제공해야 한다. 아래와 같이 Sentence 클래스에 __len__() 함수를 구현해면 len() 표준 함수 호출 시 words 리스트의 요소 개수를 문제 없이 리턴하는 것을 볼 수 있다..

class Sentence :
    def __init__(self, s) :
        self.words = s.split()

    def __len__(self) : # len() 함수를 위한 스페셜 메소드
        return len(self.words)
    
s = Sentence('Sometimes bad things happen to good people')

print(len(s))      # 7
print(s.__len__()) # 7, 이렇게도 호출 가능
반응형

배열 연산자 []

s = Sentence('Sometimes bad things happen to good people')

print(s[1])  # TypeError: 'Sentence' object is not subscriptable

이전에 작성했던 Sentence 클래스의 객체에 인덱스를 통한 접근을 시도하면 위와 같은 에러를 발생 시킨다. 인덱스를 이용해 접근하기 위해서는 __getitem__() 이라는 미리 약속된 스페셜 메소드를 제공해야 한다

class Sentence :
   def __init__(self, s) :
       self.words = s.split()

   def __getitem__(self, index) : # index 를 인자로 받아야 한다.
       return self.words[index]
       
s = Sentence('Sometimes bad things happen to good people')

print(s[1]) # bad 출력. s.__getitme__(1)과 동일

객체를 문자열로 변환

객체를 문자열로 변환하기 위해서는 __str__() 또는 __repr__() 메소드 제공해야 한다. 메소드가 지원 되지 않을때 오류 상황은 위에서 이미 많이 살펴 보았으므로 이번은 스페셜 메소드를 사용하는 코드 샘플과 각 메소드의 특징만 살펴보고 넘어 가도록 한다.

  • __str__ : 객체의 상태를 문자열로 변환, 주로 사용자에게 보여주기 위한 용도.
  • __repr__ : 디버깅 등 내부 사용 용도.
class Point :
    def __init__(self, x, y) :
        self.x = x
        self.y = y
       
    def __str__(self) :
        return f'x={self.x}, y={self.y}'
        
    def __repr__(self) :
        return f'Point({self.x}, {self.y})'

point = Point(1,2)

print(point)        # point.__str__()
print(str(point))   # point.__str__()
print(repr(point))  # point.__repr__()

별로 어려울 것이 없는 예제다. print를 사용하거나, str 표준 함수를 사용하면 기본적으로 __str__() 스페셜 메소드가 호출 된다. 하지만 repr() 함수를 호출하는 경우는 __repr__() 스페셜 메소드가 호출 된다.

주의해서 볼 사항은 __str__() 과 __repr__() 메소드 간에는 아래와 같은 백업 호출이 있다는 것이다.

  • s = repr(point) :  point.__repr__() 호출
  • s = str(point) : point.__str__() 호출, 클래스에 __str__() 스페셜 메소드가 없으면 없으면 __repr__() 호출
  • print(point) : point.__str__() 호출, 클래스에 __str__() 스페셜 메소드가 없으면 없으면 __repr__() 호출

repr() 함수는 __repr__() 스페셜 메소드만 호출 할 수 있는 반면에 str() 함수는 __str__()을 찾아 보고 없으면 __repr__()을 호출 한다. 만일 둘중 하나만 만들어야 하는 상황이라면 __repr__() 스페셜 메소드를 만들면 둘다 사용가능하다.

마치며

이상 객체의 특정 상황에 호출 되는 스페셜 메소드에 대해 알아 보았다. 다음 장 #6 callable object에서는 스페셜 메소드를 이용한 callable object를 살펴 보도록 하겠다.

부록 1. 같이 보면 좋은 글

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!