Profile picture

[Python] dataclass (데이터클래스)

JaehyoJJAng2023년 06월 02일

dataclass

파이썬 3.7부터 dataclass 라는 모듈이 추가되었다

데이터를 담는 클래스로 활용 가능하고, import 후에 @dataclass 라는 데코레이터를 사용하면 된다

dataclass 사용법

  • 자동차 정보를 담는 클래스를 예시로 기존의 클래스와 데이터클래스를 비교해보자

a. 그냥 클래스를 사용해서 자동차를 만들때

import random
import string

def generate_id() -> str:
    return "".join(random.choices(string.ascii_uppercase,k=12))

class Car:
    def __init__(self,brand: str, name: str) -> None:
        self.brand = brand
        self.name  = name
    
    def __str__(self) -> str:
        return f"{self.brand} - {self.name}"

def main() -> None:
    car : Car = Car(brand="HY",name="Sonata")
    print(car)

b. 데이터 클래스를 사용해서 자동차를 만들 때

import random
import string
from dataclass import dataclass

def generate_id() -> str:
    return "".join(random.choices(string.ascii_uppercase,k=12))

@dataclass
class Car:
    name: str
    brand: str

def main() -> None:
    car : Car = Car(name="Sonata",brand="HY") 
    print(car)

한 눈에 봐도 코드의 길이가 짧아진 것을 볼 수가 있다. instance variable을 위와 같이 작성해주면 dataclass 작성이 끝난다

기존의 클래스와 비교해서 데이터 클래스가 더 빠르고 쉬운 이유는 아래와 같다

  • 데이터 클래스가 이니셜라이저를 자동으로 생성
  • repr 메소드도 자동으로 생성해주기에 위에서와 같이 print를 찍을 때 인스턴스의 값을 보기 위해 따로 str 메소드 선언을 해주지 않아도 된다
  • 위와 같이 name: str 같은 형식으로 타입 지정을 쉽게 제공

dataclass 여러 기능

1. 디폴트 값 설정

아래와 같이 in_stock 이라는 인스턴스 변수에 boolean 값으로 True를 주면 이니셜라이저에 따로 명시하지 않아도 디폴트 값이 True로 설정된다

@dataclass
class Car:
    name: str
    brand: str
    in_stock: True

car : Car = Car(name="Sonata",brand="HY",in_stock=True)

조금 더 심화해서, 차가 발매되는 버전들을 넣을 list와 아이디에 디폴트 값을 할당해보자
주의할 점은 versions: list = [] 와 같은 식으로 줄 수는 없다. list는 mutable하기 때문에 모든 인스턴스들이 필드의 기본 값을 공유하기 때문에 허용되지 않는다.


따라서 field를 import하고 default_factory를 사용해주어야 함. 데이터클래스가 클래스를 생성할 때, default_factory=list 로 적어놓은 함수를 call해서 매번 새로운 리스트를 생성해준다

@dataclass
class Car:
    name: str
    brand: str
    in_stock: True
    versions: list = field(default_factory=list)
    id: str = field(default_factory=generate_id)

car : Car = Car(name='Sonata',brand='HY',id="my-car")

디폴트 값을 준 것이니, 당연히 클래스를 만들 때 값을 넣어주면 해당 값을 가진 객체가 생성된다


Init 옵션 주기

여기에서 위와 같이 id를 따로 생성해줄 수 없게 만들고 싶을 때는, init 옵션을 사용하자

from typing import List

@dataclass
class Car:
    name: str
    brand: str
    in_stock: True
    versions: List[str] = field(default_factory=list)
    id: str = field(init=False,default_factory=generate_id)

이렇게 init=False 옵션을 주고 이니셜라이즈에 id 값을 넣어주면 아래와 같은 에러가 발생함

TypeError: __init__() got an unexpected keyword argument 'id'

dataclass 적용 예시

  • 네이버 로그인 로직 구현 중 아이디와 패스워드를 담는 변수를 데이터클래스로 구현해보도록 하자.

dataset 디렉토리 하위에 data.py 파일을 만들어 아래처럼 코드를 작성해보도록 하자.
dataset/data.py

from dataclasses import dataclass

class LoginData():
    _id: str
    _pw: str

naver_login.py

from src.dataset.data import LoginData

class NaverLogin():
    def __init__(self, login_data: LoginData, browser) -> None:
        self.login_url: str = "https://nid.naver.com/nidlogin.login?mode=form&url=https%3A%2F%2Fwww.naver.com"
        self.login_data = login_data
        self.browser = browser

    def login(self) -> None:
        self.move_login_page()
        self.input_id()
        self.input_pw()
        self.click_login_button()

    def move_login_page(self) -> None:
        # ...

    def input_id(self) -> None:
        # ...
        pc.copy(self.login_data._id)

    def input_pw(self) -> None:
        # ...
        pc.copy(self.login_data._pw)


    def click_login_button(self) -> None:
        # ...

Loading script...