dataclass란?
파이썬 3.7부터 dataclass라는 모듈이 추가되었다.
말 그대로 데이터를 담는 클래스이고, import 후에 @dataclass 라는 데코레이터를 사용하면 된다.
기존의 방식으로 클래스를 사용하는 것과 비교했을 때, dataclass가 가지는 몇 가지 장점들이 있다.
이번 포스트에서는 dataclass의 사용법과 편리한 점들을 정리해보겠다.
dataclass 사용법
- 아이스크림 정보를 담는 클래스를 예시로 기존의 클래스와 데이터클래스를 비교해보자.
그냥 클래스를 사용해서 아이스크림을 만들 때:
import random
import string
def generate_id() -> str:
return "".join(random.choices(string.ascii_uppercase, k=12))
// 아래에서 사용예정
class Icecream:
def __init__(self, name: str, flavor: str):
self.name = name
self.flavor = flavor
def main() -> None:
icecream = Icecream(name="togegther", flavor="vanilla")
print(icecream)
if __name__ == "__main__":
main()
generate_id 라는 랜덤한 아이디를 만드는 메소드가 있고, name과 flavor를 가지는 아이스크림 클래스가 있고, main함수에서는 Icecream을 만들고 print찍는다.
main 함수에서 만든 아이스크림 인스턴스를 프린트로 찍어줄 때 <__main__.Icecream object at 0x10234bcd0> 와 같이 메모리 주소가 찍혀서 보기 좋지 않다.
str 메소드를 작성해주면 print 했을 때 클래스를 프린트했을 때 찍히는 값을 설정해줄 수 있으니 str 메소드를 작성해주자.
import random
import string
def generate_id() -> str:
return "".join(random.choices(string.ascii_uppercase, k=12))
class Icecream:
def __init__(self, name: str, flavor: str):
self.name = name
self.flavor = flavor
def __str__(self) -> str:
return f"{self.name} - {self.flavor} flavor"
def main() -> None:
icecream = Icecream(name="together", flavor="vanilla")
print(icecream)
if __name__ == "__main__":
main()
str 메소드를 위와 같이 작성해주니까 프린트문이 together - vanilla flavor 로 보기 좋게 나온다.
데이터 클래스를 사용해서 아이스크림을 만들 때:
위에서 만든 클래스와 똑같은 정보를 가지는 아이스크림 데이터클래스를 만들어보자.
import random
import string
from dataclasses import dataclass
def generate_id() -> str:
return "".join(random.choices(string.ascii_uppercase, k=12))
@dataclass
class Icecream:
name: str
flavor: str
def main() -> None:
icecream = Icecream(name="together", flavor="vanilla")
print(icecream)
if __name__ == "__main__":
main()
한 눈에 봐도 코드의 길이가 짧아졌다. instance variable을 위와 같이 작성해주면 끝이다.
기존의 클래스와 비교해서 데이터 클래스가 더 빠르고 쉬운 이유는
1) 데이터클래스가 이니셜라이저를 자동으로 만들어주고
2) __repr__ 메소드도 자동으로 생성해주기 때문에 위에서와 같이 프린트 찍을 때 인스턴스의 값을 보기 위해 따로 __str__ 메소드를
작성해주거나 하지 않아도 되고, ( 따로 메소드를 작성해주지 않아도 icecream을 프린트하면 Icecream(name='together', flavor='vanilla') 와 같이 출력됨 )
3) 위와 같이 name: str 같은 형식으로 타입을 쉽게 제공할 수 있기 떄문이다.
데이터 클래스의 간단한 사용법을 알아보았으니, 데이터클래스를 사용했을 때 얻을 수 있는 장점을 알아보자.
dataclass 의 여러가지 기능
1. 디폴트 값 설정하기
: 아래와 같이 in_stock 이라는 인스턴스 변수에 boolean 값으로 True를 주면 이니셜라이저에 따로 명시하지 않아도 디폴트 값이 True로 설정된다.
@dataclass
class Icecream:
name: str
flavor: str
in_stock: bool = True
Icecream(name='together', flavor='vanilla', in_stock=True)
조금 더 심화해서, 아이스크림이 발매되는 사이즈들을 넣을 list와 아이디에 디폴트 값을 주어보자.
여기서 주의할 점은 email_address: list = [] 와 같은 식으로 줄 수 없다는 점이다.
list는 mutable하기 때문에 모든 인스턴스들이 필드의 기본 값을 공유하기 때문에, 허용되지 않는다.
따라서 field를 import 하고 default_factory 를 사용해주어야 한다.
데이터클래스가 클래스를 생성할 때, default_factory=list 로 적어놓은 함수(타입아님)를 call 해서 매번 새로운 리스트를 생성해준다.
@dataclass
class Icecream:
name: str
flavor: str
in_stock: bool = True
sizes: list = field(default_factory=list)
id: str = field(default_factory=generate_id)
디폴트값을 준 것이니, 당연히 클래스를 만들 때 값을 넣어주면 그 값을 가진 클래스가 생성된다.
icecream = Icecream(name="together", flavor="vanilla", id="my_id")
아래는 print(icecream) 의 결과 :
Icecream(name='together', flavor='vanilla', in_stock=True, sizes=[], id='my_id')
2. Init 옵션 주기
여기에서 위와같이 id를 따로 생성해줄 수 없게 만들고 싶을 때는, init 옵션을 주면 된다.
@dataclass
class Icecream:
name: str
flavor: str
in_stock: bool = True
sizes: List[str] = field(default_factory=list)
id: str = field(init=False, default_factory=generate_id)
def main() -> None:
icecream = Icecream(name="together", flavor="vanilla", id="my_id")
print(icecream)
이렇게 init=False 옵션을 주고 이니셜라이저에 id값을 넣어주면 아래와 같은 에러가 난다.
TypeError: __init__() got an unexpected keyword argument 'id'
3. post_init 메서드 사용해서 필드 생성하기
만약에 위 Icecream 을 찾기 쉽게 유니크한 아이디와 제품명으로 이루어진 search_string 이라는 필드를 추가하고자 하면 어떻게 해야할까? 아이디는 인스턴스가 생성될 때 생성되기 때문에 동시에 값을 넣어줄 수 없다. 인스턴스가 생성된 후에 id값과 name 값이 생겨야만 만들 수 있는 필드이다. 이럴 때는 말그대로 post_init , 즉 이니셜라이즈 후의 라는 메소드를 사용하면 된다.
@dataclass
class Icecream:
name: str
flavor: str
in_stock: bool = True
sizes: List[str] = field(default_factory=list)
id: str = field(init=False, default_factory=generate_id)
search_str: str = field(init=False)
def __post_init__(self) -> None:
self.search_str = f"{self.name} - {self.id}"
Icecream(name='together', flavor='vanilla', in_stock=True, sizes=[], id='WGSJNSLLIKRX', search_str='together - WGSJNSLLIKRX')
search_str 필드의 값도 잘 생성된 것을 확인할 수 있다.
이 외에도 데이터클래스의 장점은 아주 많다.
더 많은 정보는 아래의 유투브 링크를 추천한다.
내가 매우 좋아하는 파이썬 유투버이고, 이 블로그 또한 그의 영상을 참고하여 (예시는 내가 만들었다) 정리한 것이다.
'파이썬' 카테고리의 다른 글
큰 숫자를 사용할 때 읽기 쉽게 언더바 (_) 사용하기 (0) | 2022.08.20 |
---|---|
파이썬 Global Interpreter Lock (GIL) - 1 (2) | 2022.05.01 |