스페셜 메서드(Special Method)란?
- 스페셜 메서드란, 더블 언더스코어(__)로 시작하고 끝나는 메서드
- Dunder Method(double underscore method)라고도 불린다.
- 특별한 기능을 수행하며, Python 인터프리터에 의해 특정한 시점 또는 상황에서 자동으로 호출된다.
- 클래스의 특정 동작을 커스터마이즈할 수 있게 해준다.
이제 대표적인 스페셜 메서드와 예제 코드를 설명한다.
__len__
__len__() 메서드는 객체 속성에 대해 그 길이를 반환하는 스페셜 메서드다.
class Sentence:
def __init__(self, sentence):
self.sentence = sentence
def __len__(self):
return len(sentence)
s = Sentence("In the beginning God created the heavens and the earth.")
print(len(s)) # print(Sentence.__len__(s))
>> 55
__getitem__
__getitem__() 메서드는 객체에 대해 특정 인덱스에 있는 데이터를 반환하는 메서드다.
class Sentence:
def __init__(self, sentence):
self.sentence = sentence
def __len__(self):
return len(sentence)
def __getitem__(self, idx):
return self.sentence[idx]
s = Sentence("In the beginning God created the heavens and the earth.")
print(s[0]) # print(Sentence.__getitem__(s, 0))
>> I
__iter__
__iter__() 메서드는 반복자(iterator)를 반환하는 스페셜 메서드다.
class Sentence:
def __init__(self, sentence):
self.sentence = sentence
def __len__(self):
return len(sentence)
def __getitem__(self, idx):
return self.sentence[idx]
def __iter__(self):
return iter(self.sentence)
s = Sentence("In the beginning God created the heavens and the earth.")
for word in s:
print(word)
>> I
>> n
>>
>> t
>> h
>> e
>>
>> b
__str__
__str__() 메서드는 객체를 문자열화하는 스페셜 메서드다.
class MyBlog:
def __init__(self, blogname, url, category):
self.blogname = blogname
self.url = url
self.category = category
def __str__(self):
return f"Blog name : {self.blogname}, URL : {self. url}, Category : {self.category}"
bithub = MyBlog("bithub", "bithub.tistory.com", "IT")
print(bithub) # print(str(bithub)) -> print(MyBlog.__str__(bithub))
>> Blog name : bithub, URL : bithub.tistory.com, Category : IT
* 참고 : print() 함수는 내부적으로 출력 대상에 str() 함수를 적용한다.
__repr__
__repr__() 메서드 역시 객체를 문자열화하는 스페셜 메서드다.
__str__와 __repr__의 차이점
- __str__ : 라이브러리를 사용자들이 디버깅 목적으로 사용되며, 객체의 비공식적인 정보를 출력한다.
- __repr__ : 라이브러리를 개발자들이 디버깅 및 개발 목적으로 사용되며, 객체의 공식적인 정보를 출력한다.
print(str(123))
print(repr(123))
print(str(3.14))
print(repr(3.14))
print(str("hello"))
print(repr("hello"))
>> 123
>> 123
>> 3.14
>> 3.14
>> hello
>> 'hello'
위 코드만 봤을 때는 __str__과 __repr__의 큰 차이가 없어 보인다.
하지만 아래 코드를 보자.
import datetime
now = datetime.datetime.now()
print(str(now))
print(repr(now))
>> 2024-03-28 16:13:15.000683
>> datetime.datetime(2024, 3, 28, 16, 13, 15, 683)
str(now)는 간결한 날짜시간 형태로 출력되는 반면,
repr(now)는 객체 생성 코드가 그대로 담겨 출력된다.
그래서 eval() 함수 사용 시 str() 함수 대신 repr() 함수를 사용한다.
import datetime
now = datetime.datetime.now()
print(eval(str(now))) # error
print(eval(repr(now))) # 2024-02-28 16:21:10.913033
* eval() 함수는 문자열로 된 명령어를 문자로 받아서 해당 명령어를 실행하는 함수다.
예시)
eval("print("hello")")
>> hello
따라서 __repr__ 함수를 구현할 때 반환값이 반드시 eval() 함수의 인자로 적합한 값이여야함을 명심하고 구현해야 한다.
* __repr__ 구현 예제
class MyBlog:
def __init__(self, blogname, url, category):
self.blogname = blogname
self.url = url
self.category = category
def __str__(self):
return f"Blog name : {self.blogname}, URL : {self. url}, Category : {self.category}"
def __repr__(self):
return f"MyBlog('{self.blogname}', '{self.url}', '{self.category}')"
bithub = MyBlog("bithub", "bithub.tistory.com", "IT")
bithub_clone = eval(repr(bithub))
print(bithub)
print(bithub_clone)
>> Blog name : bithub, URL : bithub.tistory.com, Category : IT
>> Blog name : bithub, URL : bithub.tistory.com, Category : IT
__new__
- __new__() 메서드는 객체가 생성될 때 호출되는 스페셜 메서드다.
- 기본적으로 클래스 메서드로 선언된다. 이유는 객체가 생성될 때 호출되므로 객체 없이 호출될 수 있도록 하기 위함이다.
- 클래스 메서드이기 때문에 cls를 반드시 인자로 가져야 한다.
- @classmethod 데커레이터를 따로 명시해줄 필요 없다.
- 반드시 객체를 반환해야 한다. 객체를 반환하지 않으면 객체가 생성된 후 호출되는 __init__()이 호출되지 않는다.
* __init__() 메서드와 차이점
- __init__()은 객체가 생성된 후 호출된다.
- __new__()는 객체가 생성되기 전 호출되고 객체를 생성하여 반환한다.
class MyBlog:
def __new__(cls):
print("MyBlog.__new__")
return object.__new__(cls)
def __init__(self):
print("MyBlog.__init__")
pass
bithub = MyBlog()
>> MyBlog.__new__
>> MyBlog.__init__
* 유틸리티 클래스의 경우 클래스를 반환하도록 하여 객체가 생성되지 않도록 할 수 있다.
class Calculator:
def __new__(cls):
return cls
@classmethod
def add(cls, a, b):
return a + b
@classmethod
def subtract(cls, a, b):
return a - b
print(Calculator.add(2,2))
calc = Calculator()
print(calc, calc.add(2, 2))
>> 4
>> <class '__main__.Calculator'> 4
calc 변수에 객체가 아닌 Class가 담긴 것을 확인할 수 있다.
'Python' 카테고리의 다른 글
Python 연결 리스트(Linked List) (0) | 2024.03.29 |
---|---|
Python 싱글턴 패턴(Singleton Pattern), 반복자 패턴(Iterator Pattern), 데코레이터 패턴(Decorator Pattern) (0) | 2024.03.29 |
Python 클래스, 객체 (0) | 2024.03.27 |
Python 함수 선언 방법, 변수 지역성 (0) | 2024.03.27 |
Python 이터러블(iterable)과 반복자(iterator) (0) | 2024.03.27 |