일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 자연어처리
- SQL코테
- 코딩테스트
- inner join
- GRU
- NLP
- Window Function
- 그룹바이
- 짝수
- 논문리뷰
- 자연어 논문 리뷰
- 자연어 논문
- nlp논문
- t분포
- Statistics
- airflow
- HackerRank
- 카이제곱분포
- sigmoid
- SQL 날짜 데이터
- CASE
- 설명의무
- sql
- 표준편차
- leetcode
- torch
- update
- 서브쿼리
- MySQL
- LSTM
- Today
- Total
HAZEL
[ Python : Data Model ] 네임드 튜플, magic 메소드, 오버로딩, 오버라이딩 본문
- FastCampus 파이썬 웹 개발 올인원 패키지 Online. 강의 중, Advanced part 를 듣고 정리한 글입니다.
Chapter 02 : Data Model
1. 튜플 vs 네임드 튜플
01. 튜플
: 리스트와 다르게 변하지 않는 자료형을 말한다. 따라서, 리스트보다 속도가 더 빠르다.
pt1 = (1.0 , 5.0)
pt2 = tuple(2.5 , 1.5)
02. 네임드 튜플
: 네임드 튜플은 튜플과 마찬가지로, 변하지 않는 성질을 가지고 있다.
뿐만 아니라, 인덱스를 통한 접근과 키 값을 통한 접근 모두 가능하다.
아래의 예시와 같이, 클래스처럼 튜플을 사용할 수 있다. - 실제로, 타입을 찍어보면 클래스 형태로 되어있다.
# 네임드 튜플 사용
from collections import namedtuple
# 네임드 튜플 선언
Point = namedtuple('Point', 'x y')
# 두점 선언
pt1 = Point(1.0 , 5.0)
pt2 = Point(2.5 , 1.5)
line_length2 = sqrt((pt2.x - pt1.x) ** 2 + (pt2.y - pt1.y ) **2)
1) 네임드 튜플을 선언하는 방법
: 네임드 튜플을 선언 할 때, 이름과 변수를 같게 하는 것이 규칙이다.
Point1 = namedtuple('Point',[ 'x', 'y']) # 리스트 넣기
Point2 = namedtuple('Point', 'x, y') # 문자 사이에 , 넣기
Point3 = namedtuple('Point', 'x y') # 공백을 넣어도되지만, 가능하면 리스트나 , 를 넣어주기
* 예외 상황 : 튜플은 중복을 허용하지 않기 때문에, 같은 값을 넣거나 예약어 사용하면 에러가 난다.
- 아래와 같은 코드의 경우, x 가 2개 들어가있고, class 는 예약어이므로 원래는 에러가 난다.
하지만 아래와 같이 rename = True 를 설정하면, 에러가 발생하지 않는다.
rename = True 의 의미는, 변수의 의미가 잘못됬다면 알아서 이름을 지정해줘도 된다 라는 뜻이다.
# rename = False 가 디폴트이다.
Point4 = namedtuple('Point', 'x y x class', rename= True)
위의 코드 결과, 아래와 같이 같은 값인 x 와 예약어의 이름이 _2, _3 으로 바뀐것을 확인할 수 있다.
Point(x=10, y=20, _2=30, _3=40)
2 ) 네임드 튜플의 객체를 생성하는 방법
: 위에서 선언한 네임드 튜플에 데이터를 넣어서 객체를 생성하는 방법
# dict to unpacking
temp_dict = { 'x' : 10, 'y' : 20}
p1 = Point1(x = 1 , y = 3) # ( 1 , 3 ) 를 하면 순서대로 넣어지는데 지정해도됨
p2 = Point2(8 , 5)
p3 = Point3(56 , y = 20) # 하나만 지정해도 된다.
p4 = Point4(10 , 20, 30 ,40)
p5 = Point3(**temp_dict) # Point(x=8, y=99) 언페킹을 이용해서도 할 수 있음
3 ) 네임드 튜플의 사용
- 튜플이라는 이름처럼, 인덱싱도 가능하다.
- 하지만, 인덱싱 보다는 클래스 변수 접근 방식처럼 사용하는 것이 일반적이다.
print(p1.x + p2.y)
4 ) 네임드 튜플 메소드
a. _make( ) : 새로운 객체를 생성하는 메소드
temp = [2,3]
p4 = Point1._make(temp)
# output : Point(x=52, y=38)
b. _fields( ) : 필드 네임을 확인하는 메소드
print( p1._fields, p2._fields, p3._fields)
# output : ('x', 'y') ('x', 'y') ('x', 'y')
c. _asdict( ) : 정렬된 딕셔너리로 반환
print('ex4-3 : ', p1._asdict(), p2._asdict(), p4._asdict())
# output : OrderedDict([('x', 10), ('y', 35)]) OrderedDict([('x', 20), ('y', 40)]) OrderedDict([('x', 52), ('y', 38)])
print(dict(p1._asdict())) # 딕셔너리로 정렬 가능
# output : {'x': 10, 'y': 35}
d. _replace( ) : 수정된 '새로운' 객체 반환 - id 값이 달라진다.
print(p2._replace(y =100))
# output : Point(x=20, y=100)
2. 매직 메소드
- '메소드(method)' : 클래스 안에 정의된 함수
- 매직 메소드 : 메소드 중에서 __로 시작해서 __로 끝나는 메소드들
01. 모든 속성 및 메소드를 출력
: dir() 로 감싸면 그 함수 / 클래스에 들어있는 메소드를 출력할 수 있다.
print(dir(int))
# output : ['__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']
02. 다양한 매직 메소드
- __add__() : + 와 같은 기능을 하는 메소드
n.__add__(200)
- __doc__ : 설명해주는 메소드
n.__doc__
- __bool__() : Ture, False 로 나타내는 메소드
n.__bool__(), bool(n)
- __mul__(): 곱해주는 메소드
n * 100, n.__mul__(100)
03. 클래스 내부에서 오버로딩과 오버라이딩
: 클래스 안에서, 오버로딩과 오버라이딩을 통해서, 메소드를 직접 새로 구현할 수 있다.
- 오버라이딩 이란?
: 상위 클래스가 가지고 있는 멤버 변수가 하위 클래스로 상속되는 것처럼, 상위 클래스가 가지고 있는 메서드를 하위 클래스에서 재정의 하여 사용하는 것. 즉, 이름은 같으나 상속받은 메서드를 새로 정의해서 다시 사용한다는 개념이다.
: 메소드 이름이 같아야하고, 파라미터 개수나 자료형이 동일해야한다. 하지만 내용적으로는 달라도 된다.
- 오버 로딩 이란 ?
: 같은 이름의 함수(메서드)를 여러개 정의하고 , 매개변수의 유형과 개수를 다르게 하여 다양한 유형의 호출에 응답할 수 있게 하는 것
class Office:
def __init__(self, name, work):
self._name = name
self._work = work
# 오버라이딩 : 이미 가지고 있는것을 우리가 다시 선언해주는 것이다.
# 원래 선언해주지 않는다면, 그냥 string으로 나올텐데, 오버라이딩을 해줌으로 아래처럼 정보가 출력된다.
def __str__(self):
return 'Office Class Info : {} {}'.format(self._name, self._work)
# 오버로딩
def __ge__(self, x):
print('Called >> __ge__ Method')
if self._work >= x._work:
return True
else:
return False
def __le__(self , x):
print('Called >> __le__ Method')
if self._work <= x._work:
return True
else:
return False
def __sub__(self ,x ):
print('Called >> __sub__ Method')
return self._work - x._work
위에 코드에서 왜?! __str__ 은 오버라이딩 이고, 나머지 __ge__, __ le__ , __sub__ 는 오버로딩 이냐는 것은,
위에서 만들어 놓은 메소드를 주석 처리하고, 결과를 실행해보면 나온다.
1 ) __str__ 를 주석 처리 해보면!? == 오버라이딩을 주석 처리해 보면?!
: 위에서 언급했듯이, 오버라이딩은 이미 상위 클래스에서 만들어진 것을 받아온 것이다.
따라서, 내가 만들어준 함수에서 선언하지 않아도 실행 된다 ! ( 다만 알수없는 함수 형태로 반환 된다 )
o1 = Office('Hazel', 90)
print(o1)
# output : <__main__.Office object at 0x105f1b130>
위의 output을 보면, 에러는 안나지만, <__main__.Office object at 0x105f1b130> 로 알수 없는 결과물을 받을 수 있다.
이것을 내가 이해할 수 있는 언어로 볼려면, '오버라이딩'을 해주어야 한다는 것이다.
주석을 다시 해제 하고 출력을 하면! 위에서 오버라이딩 해준 문자열로 나오게 되는 것을 확인 할 수있다.
print(o1)
# output : Office Class Info : Hazel 90
2) __ge__ 를 주석 처리 해보면 !? == 오버로딩을 주석 처리를 해보면 ?!
: 만약 __ge__ 라는 메소드를 만들어 놓지 않았다면, 관련 함수를 실행 했을 때, 에러가 난다.
print('ex2-1 : ', o1 >= o2 )
# TypeError: '>=' not supported between instances of 'Office' and 'Office'
위에서의 작성한 클래스 같은 경우, 모두 다른 이름으로 함수를 만들었지만, 오버로딩(overloading)은 이름은 같은 함수를 여러개 만들 수 있다. 즉, 이름은 같지만 파라미터 갯수나 타입을 조정해서 다른 메소드를 중복으로 선언이 가능하다는 의미이다.