파이썬에서는 객체에서 불러올 수 있는 메소드 중
__메소드이름__ 이런 식으로 더블언더스코어가 양쪽으로 붙어있는 메소드들이 있습니다.
이들은 매직 메소드 (혹은 스페셜 메소드, 혹은 던더 메소드) 라고 합니다.
파이썬의 매직메소드는 프로그래머에 의해 직접적으로 쓰이기 보다는
객체에 어떤 액션을 취하느냐에 따라 클래스에서 내부적으로 처리됩니다.
예를 들면, 우리는 a 와 b의 값을 더할때 a + b라고 표기합니다.
그런데 사실 a + b는 a 객체가 가지고 있는 메소드 __add__()에 의해 실행됩니다.
a+b
# 위 아래 코드는 동일
a.__add__(b)
각 객체가 가지고 있는 매직메소드는 dir() 를 통해 확인할 수 있습니다.
print(dir(int))
# ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__',
# '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__',
# '__float__', '__floor__', '__floordiv__', '__format__', '__ge__',
# '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__',
# '__init__', '__init_subclass__', '__int__', '__invert__', '__le__',
# '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__',
# '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__',
# '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__',
# '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__',
# '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__',
# '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__',
# '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length',
# 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
파이썬의 오퍼레이터에 대한 오버로딩을 구현할 수 있도록 돕습니다.
즉, 사용자 정의의 클래스가 빌트인 오퍼레이터 기능을 커스터마이즈해서 사용할 수 있습니다.
예시)
기본 빌트인 타입 중 int와 string은 + 연산이 불가능하죠.
x = int(1)
print(x + '1')
# 결과: TypeError: unsupported operand type(s) for +: 'int' and 'str'
임의의 클래스를 구현하여 매직메소드를 사용하면
int와 string의 + 연산결과를 얻을 수 있습니다.
#int를 부모클래스로 가진다
class Customized(int):
# 👇str input을 받아 + 연산을 하면 str 타입으로 합체
def __add__(self, plus: str) -> str:
return str(self.real) + plus
x = Customized(1)
print(x + '1')
#결과: '11'
가장 유명한 던더 메소드는 아마 __init__()일 것입니다.
그리고 __init__()과 함께 constructor 역할을 하는 __new__()라는 메소드가 있습니다.
__new__()라는 메소드는 새로운 인스턴스를 생성하고 (return하고),
__init__()이 return된 인스턴스를 인자에 맞게 커스터마이즈(초기화)합니다.
__new__() 는 static method이며, 일반적인 경우 굳이 오버라이드 하지 않습니다.
형식과 사용법은 아래와 같습니다.
#__new__() 형식
class ClassName:
def __new__(cls, *args, **kwargs):
#...중간 코드...#
return super(ClassName, cls).__new__(cls, *args, **kwargs)
# 적용 예시
class MyClass(object):
def __new__(cls, interger:int, array:list):
print('인스턴스 생성중...')
return super(MyStr, cls).__new__(cls, interger, array)
def __init__(self, interger, array):
self.interger = interger
self.array = array
지금까지 알아본 내용을 토대로
간단하고 조악하며 쓸모없는 클래스를 만들어보았습니다.
저번에 파이썬의 불변객체, 가변객체에 대해 알아본 적이 있는데요,
불변객체는 item assignment가 원칙적으로 적용이 안되었죠.
string = 'string'
string[0] = 'xx'
#결과: TypeError: 'str' object does not support item assignment
str에 item assignment가 되는것처럼 보이게 하는 str의 서브클래스를 만들어보았습니다.
#👇str의 서브클래스
class MyStr(str):
#👇as_array는 self를 한 letter씩 쪼갠 값들을 가진다
def __init__(self, as_array):
self.as_array = list([_ for _ in self])
def __setitem__(self, index, value):
self.as_array[index] = str(value)
def __str__(self):
return ''.join(self.as_array)
x = MyStr('Good Evening!')
print(x)
x[5:] = 123456789
print(x)
x[5:] = 'Morning~!'
print(x)
#👇부모클래스의 메소드도 잘 동작하는가?
print(x.lower())
# Good Evening!
# Good 123456789
# Good Morning~!
# good evening!
def __setitem__(self, index, value):
self.as_array[index] = str(value)
__setitem__()는 보통 가변객체(list, dict)가 가진 매직 메소드이며,
두번째 인자가 index 혹은 key가 되고, 세번째 인자가 해당 index, key의 값이 됩니다.
def __getitem__(self, index):
return self.as_array[index]
set과 반대로 두번째 인자에 위치한 값을 가져옵니다.
def __str__(self):
return ''.join(self.as_array)
인스턴스를 이해하기 쉬운 형태의 string으로 표현합니다.
출력값으로 string이 오지 않으면 에러가 발생합니다. (TypeError: __str__ returned non-string)
__str__() 메소드는 여러모로 유용하게 쓰일 수 있습니다.
예를 들어 사용자정의 클래스를 print()하면
객체의 내용이 아닌 메모리 주소만 표기됩니다.
class Class():
def __init__(self, status):
self.status = status
cls_ = Class('hungry')
print(cls_)
# <__main__.Class object at 0x7ff49e6448b0>
여기서 __str__() 매직 메소드를 이용하면 좀 더 사용자의 편의에 맞게 print()를 쓸 수 있습니다.
class Class():
def __init__(self, status):
self.status = status
def __str__(self):
return 'status: ' + str(self.status)
cls_ = Class('hungry')
print(cls_)
# status: hungry
그 외 다양한 매직메소드의 정보들은 아래 사이트에 참고로 걸어놓았습니다!
참고
docs.python.org/ko/3.7/reference/datamodel.html#special-method-names
www.geeksforgeeks.org/__new__-in-python/
[python]함수의 인자 형태와 순서 / (non)default value parameter, *args, **kwargs (0) | 2021.03.17 |
---|---|
[Python] 문자열을 붙이는 다양한 방법 (string concatenation) (1) | 2021.03.17 |
파이썬 예외처리 (try, except, else, finally, assert) (0) | 2021.02.26 |
가변객체(mutable)와 불변객체(immutable) / 파이썬 (2) | 2021.02.19 |
객체지향 프로그래밍과 그 특징(추상화, 캡슐화, 상속성, 다형성) / 파이썬 예시 (2) | 2021.02.19 |
댓글 영역