상세 컨텐츠

본문 제목

파이썬 매직 메소드(던더 메소드)

언어/Python

by moonionn 2021. 2. 28. 04:57

본문

 

더블언더스코어를 낀 메소드의 정체

파이썬에서는 객체에서 불러올 수 있는 메소드 중

__메소드이름__ 이런 식으로 더블언더스코어가 양쪽으로 붙어있는 메소드들이 있습니다.

이들은 매직 메소드 (혹은 스페셜 메소드, 혹은 던더 메소드) 라고 합니다.

 

파이썬의 매직메소드는 프로그래머에 의해 직접적으로 쓰이기 보다는

객체에 어떤 액션을 취하느냐에 따라 클래스에서 내부적으로 처리됩니다.

 

예를 들면, 우리는 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!

 

__setitem__()

def __setitem__(self, index, value):
    self.as_array[index] = str(value)

__setitem__()는 보통 가변객체(list, dict)가 가진 매직 메소드이며,

두번째 인자가 index 혹은 key가 되고, 세번째 인자가 해당 index, key의 값이 됩니다.

 

+ 자매품 __getitem__()

def __getitem__(self, index):
    return self.as_array[index]

set과 반대로 두번째 인자에 위치한 값을 가져옵니다.

 

__str__()

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

 

 

그 외 다양한 매직메소드의 정보들은 아래 사이트에 참고로 걸어놓았습니다! 

 

 

참고

www.tutorialsteacher.com/python/magic-methods-in-python#:~:text=Magic%20methods%20in%20Python%20are,class%20on%20a%20certain%20action.

 

Magic or Dunder Methods in Python

Python - Magic or Dunder Methods Magic methods in Python are the special methods that start and end with the double underscores. They are also called dunder methods. Magic methods are not meant to be invoked directly by you, but the invocation happens inte

www.tutorialsteacher.com

docs.python.org/ko/3.7/reference/datamodel.html#special-method-names

 

3. 데이터 모델 — Python 3.7.10 문서

클래스는 특별한 이름의 메서드들을 정의함으로써 특별한 문법 (산술 연산이나 인덱싱이나 슬라이딩 같은)에 의해 시작되는 어떤 연산들을 구현할 수 있습니다. 이것이 연산자 오버 로딩 (operato

docs.python.org

www.geeksforgeeks.org/__new__-in-python/

 

__new__ in Python - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

schoolofweb.net/blog/posts/%ED%8C%8C%EC%9D%B4%EC%8D%AC-oop-part-6-%EB%A7%A4%EC%A7%81-%EB%A9%94%EC%86%8C%EB%93%9C-magic-method/

 

SchoolofWeb :: 파이썬 - OOP Part 6. 매직 메소드 (Magic Method)

파이썬 객체 지향 프로그래밍(Object Oriented Programming) 강좌 - Part 6. 매직 메소드 (Magic Method)

schoolofweb.net

 

관련글 더보기

댓글 영역