일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- gather_nd
- Counterfactual Explanations
- tensorflow text
- login crawling
- airflow subdag
- chatGPT
- GenericGBQException
- Airflow
- top_k
- XAI
- API
- API Gateway
- requests
- hadoop
- flask
- GCP
- 공분산
- BigQuery
- youtube data
- 상관관계
- subdag
- UDF
- 유튜브 API
- grad-cam
- TensorFlow
- session 유지
- correlation
- integrated gradient
- spark udf
- Retry
- Today
- Total
데이터과학 삼학년
Magic method (매직 메서드) 본문
Magic method
파이썬 class 안에 메서드를 입력할때 일명 던더(더블언더바) 함수를 붙이는 경우가 있다.
가령
__init__ , __str__ 등이 그렇다.
여기서 던더함수는 가장 대표적인 매직 메서드이다. 즉 던더함수를 쓰면 어떤 정해진 틀에 해당 함수를 정의한다. 라고 보면 된다.
예를 들어
__init__ : 해당 class명으로 instance를 만들때 초기 설정값
__str__, __repr__ : print() 함수를 쓸 때 호출할 값 설정
이다.
아래 코드처럼 __init__ 을 사용하여 class의 instance를 만들때 넣어줄 초기값을 지정하는 것과 같다.
즉, 함수명은 __init__ 으로 지정하였지만 실제 해당 함수를 호출할때는 클래스명() 로
정의한 함수명으로 호출하지 않는다는 것이다. --> 즉 던더함수는 호출할 함수명이 미리 정의되어있다.
# -*- coding: utf-8 -*-
class Dog(object):
def __init__(self, name, age):
print('이름: {}, 나이: {}'.format(name, age))
dog_1 = Dog('Pink', '12')
여기서 + 연산자의 경우는 __add__ 로 함수를 정의해주면 되는데,
이렇게 매직 메서드를 호출하여 오버로드하는 방식이 class에서 던더함수를 쓰는 이유이다.
기본적으로 class에서 어떠한 instance를 만들었을때, 해당 instance가 가지고 있는 매직메소드를 확인하는 방법은 dir() 함수를 사용하는 것이다.
# -*- coding: utf-8 -*-
# int를 부모 클래스로 가진 새로운 클래스 생성
class MyInt(int):
pass
# 인스턴스 생성
my_num = MyInt(5)
# 매직 메소드를 가지고 있는지 확인
print(dir(my_num))
====================
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__',
'__delattr__', '__dict__', '__dir__', '__divmod__', '__doc__', '__eq__',
'__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__',
'__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__int__', '__invert__',
'__le__', '__lshift__', '__lt__', '__mod__', '__module__', '__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__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag',
'numerator', 'real', 'to_bytes']
매직 메서드를 이용하여 '+' 연산자에 새로운 기능을 추가해보자
# -*- coding: utf-8 -*-
# int를 부모 클래스로 가진 새로운 클래스 생성
class MyInt(int):
# __add__ 변경
def __add__(self, other):
return '{} 더하기 {} 는 {} 입니다'.format(self.real, other.real, self.real + other.real)
# 인스턴스 생성
my_num = MyInt(5)
print(my_num + 5)
=====================
5 더하기 5 는 10 입니다
이렇게 built-in type인 int, str, list, dict등은 사용자들의 편리함을 위해서 자신에 타입에 맞게 각종 오퍼레이터를 오버로딩하는 매직 메소드를 포함하고 있다.
매직 메소드를 이용하여 연산을 한 코드는 아래와 가탇.
# -*- coding: utf-8 -*-
# 리스트의 덧셈
print([1,2,3] + [4,5,6])
# 매직 메소드로 덧셈
print([1,2,3].__add__([4,5,6]))
# 사전의 길이 확인
print(len({'one':1, 'two': 2, 'three': 3}))
# 매직 메소드로 사전의 길이 확인
print({'one':1, 'two': 2, 'three': 3}.__len__())
Magic method의 필요성
자! 그럼 class에서 매직 메서드를 정의하여 해당 class를 좀 더 유용하게 써보자.
예를 들면 tensorflow의 * 연산이 matmul로 되어 있는 것도 magic method를 사용한 것이라고 볼 수 있다.
일반적으로 class 객체를 만들고 print를 하면 할당된 메모리 주소가 나오게 된다.
# -*- coding: utf-8 -*-
class Food(object):
def __init__(self, name, price):
self.name = name
self.price = price
food_1 = Food('아이스크림', 3000)
# 인스턴스 출력
print(food_1)
==============
<__main__.Food object at 0x101a07710>
하지만 print(객체)를 했을 때 객체의 정보를 보고 싶다면 메직메서드를 정의해줘야만 한다. 바로 아래코드처럼!
# -*- coding: utf-8 -*-
class Food(object):
def __init__(self, name, price):
self.name = name
self.price = price
def __str__(self):
return '아이템: {}, 가격: {}'.format(self.name, self.price)
food_1 = Food('아이스크림', 3000)
# 인스턴스 출력
print(food_1)
================
템: 아이스크림, 가격: 3000
비교 연산자 역시
매직 메서드를 정의해줘야한다. 그렇지 않으면 단순히 메모리 주소를 비교한 결과가 출력된다.
아래 코드가 매직메서드를 정의하지 않았을때 잘못된 비교 연산을 보여준다.
# -*- coding: utf-8 -*-
class Food(object):
def __init__(self, name, price):
self.name = name
self.price = price
food_1 = Food('아이스크림', 3000)
food_2 = Food('햄버거', 5000)
# food_2가 food_1보다 큰지 확인
print(food_1)
print(food_2)
print(food_1 < food_2)
==============
<__main__.Food object at 0x103cc0b50>
<__main__.Food object at 0x1039b5a90>
False
그렇다면
비교 연산을 내가 원하는 값으로 하려면 아래처럼 매직 메서드를 정의해줘야한다. 비교연산자 역시!
# -*- coding: utf-8 -*-
class Food(object):
def __init__(self, name, price):
self.name = name
self.price = price
def __lt__(self, other):
if self.price < other.price:
return True
else:
return False
food_1 = Food('아이스크림', 3000)
food_2 = Food('햄버거', 5000)
food_3 = Food('콜라', 2000)
# food_2가 food_1보다 큰지 확인
print(food_1 < food_2) # 3000 < 5000
print(food_2 < food_3) # 5000 < 2000
===========
True
False
__add__ 메서드 역시 마찬가지다.
매직 메서드를 정의하지 않고 그저 연산을 하게 되면 TypeError 가 나타나게 될것이다. 메모리주소끼리 더할 수가 없기 때문이다.
아래 코드처럼 __add__ 연산자도 더해줘야한다.
# -*- coding: utf-8 -*-
class Food(object):
def __init__(self, name, price):
self.name = name
self.price = price
def __add__(self, other):
return self.price + other.price
food_1 = Food('아이스크림', 3000)
food_2 = Food('햄버거', 5000)
print(food_1 + food_2)
생각보다 이렇게 일일히 매직 메서드를 정의해줘야하는 불편함은 있지만.
이렇게 정의해줌으로써 나만의 코드 완성과 프로젝트의 성격에 맞게 코드를 재구성할 수 있는 장점이 있다.
Magic method 모음
Binary Operators
Operator | Method |
+ | object.__add__(self, other) |
- | object.__sub__(self, other) |
* | object.__mul__(self, other) |
// | object.__floordiv__(self, other) |
/ | object.__div__(self, other) |
% | object.__mod__(self, other) |
** | object.__pow__(self, other[, modulo]) |
>> | object.__lshift__(self, other) |
<< | object.__rshift__(self, other) |
& | object.__and__(self, other) |
^ | object.__xor__(self, other) |
| | object.__or__(self, other) |
Extended Assignments
Operator | Method |
+= | object.__iadd__(self, other) |
-= | object.__isub__(self, other) |
*= | object.__imul__(self, other) |
/= | object.__idiv__(self, other) |
//= | object.__ifloordiv__(self, other) |
%= | object.__imod__(self, other) |
**= | object.__ipow__(self, other[, modulo]) |
<<= | object.__ilshift__(self, other) |
>>= | object.__irshift__(self, other) |
&= | object.__iand__(self, other) |
^= | object.__ixor__(self, other) |
|= | object.__ior__(self, other) |
Unary Operators
Operator | Method |
- | object.__neg__(self) |
+ | object.__pos__(self) |
abs() | object.__abs__(self) |
~ | object.__invert__(self) |
complex() | object.__complex__(self) |
int() | object.__int__(self) |
long() | object.__long__(self) |
float() | object.__float__(self) |
oct() | object.__oct__(self) |
hex() | object.__hex__(self) |
Comparison Operators
Operator | Method |
< | object.__lt__(self, other) |
<= | object.__le__(self, other) |
== | object.__eq__(self, other) |
!= | object.__ne__(self, other) |
>= | object.__ge__(self, other) |
> | object.__gt__(self, other) |
출처 : http://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
'Python' 카테고리의 다른 글
argparse 리스트(list), boolean(True or False) 를 파라미터로 받는 방법 (0) | 2020.07.09 |
---|---|
First Class Function (일급 함수) (0) | 2020.04.13 |
Inheritance and Subclass (상속과 서브 클래스) (0) | 2020.04.06 |
Instance method, Class method, Static method (1) | 2020.04.04 |
문자열 포맷팅 (% operator, str.format, f-string) (0) | 2020.04.02 |