데이터 클래스(dataclasses)

Sawol·2021년 6월 13일
1

I Need Python

목록 보기
12/13
post-thumbnail

데이터 클래스

데이터 클래스 정의

  • 파이썬 3.7 버전에 추가된 기능
  • 데코레이터
  • 특정한 매직 메서드를 자동으로 만들어 줌
  • 변수 어노테이션이 붙어 있는 어트리뷰트(클래스 내의 변수나 메서드)를 찾음
    이를 필드라고 부름
from dataclasses import dataclass

@dataclass
class C:
    a: int       # 필드 1
    b: int = 0   # 필드 2

사용하는 이유

  • 개발자가 반복적으로 사용하는 매직 메서드를 @dataclass() 데코레이션만 붙이면 알아서 생성해주기 때문에 편리함

데이터 클래스 사용해보기

데이터 클래스를 사용하지 않았을 때

class Book:
    def __init__(self, name: str, weight: float, shelf_id:int = 0):
        self.name = name
        self.weight = weight # in grams, for calculating shipping
        self.shelf_id = shelf_id
        
test = Book('I need Python',1.5,1267)
print(test)
>>> <__main__.Book object at 0x0000014020474DC8>

__repr__ 메서드가 정의되지 않았기 때문에 인스턴스를 실행하면 Book 클래스의 메모리 값이 나온다.

class Book:
    def __init__(self, name: str, weight: float, shelf_id:int = 0):
        self.name = name
        self.weight = weight # in grams, for calculating shipping
        self.shelf_id = shelf_id
        
    def __repr__(self):
        return (f"Book(name={self.name!r},weight = {self.weight!r}, shelf_id = {self.shelf_id!r})")

test = Book('I need Python',1.5,1267)
print(test)
>>> Book(name='I need Python',weight = 1.5, shelf_id = 1267)

__repr__ 메서드를 정의하고 인스턴스를 실행하면 정의된 파라미터 값들을 확인할 수 있다.

데이터 클래스를 사용했을 때

하지만 매번 사용하는 모든 클래스에 매직 메서드를 정의하는 것은 귀찮고 오타로 인한 에러 발생의 위험이 있다. 그렇기 때문에 데이터 클래스라는 데코레이터를 통해 간단히 매직 메서드를 정의할 수 있다.

from dataclasses import dataclass

@dataclass
class Book:
    name: str
    weight: float
    shelf_id: int = 0

test = Book('I need Python',1.5,1267)
print(test)
>>> Book(name='I need Python', weight=1.5, shelf_id=1267)

굉장히 코드가 간결해진것을 볼 수 있다. 참고로 init 메서드 또한, 데이터 클래스에서 자동으로 생성해주기 때문에 따로 정의하지 않아도 아래와 같이 정상적으로 실행된다.

# no dataclass
class Number:
__init__(self, val):
 self.val = val
 
>>> one = Number(1)
>>> one.val
>>> 1

# use dataclass
@dataclass
class Number:
 val:int 
 
>>> one = Number(1)
>>> one.val
>>> 1

만약 dataclass를 사용하며 init을 사용하고 싶으면 __post_init__을 사용하면 된다. 기능은 init과 동일하며 단지, dataclass에서 자동으로 생성한 init__post_init__을 호출해준다.

import math
@dataclass
class FloatNumber:
    val: float = 0.0
 
    def __post_init__(self):
        self.decimal, self.integer = math.modf(self.val)
 
>>> a = Number(2.2)
>>> a.val
>>> 2.2
>>> a.integer
>>> 2.0
>>> a.decimal
>>> 0.2

데이터 클래스의 매개변수

init

  • True가 기본 값
  • True__init__ 메서드가 생성됨
  • 클래스가 이미 __init__ 메서드를 정의 했으면 이 매개변수는 무시됨

repr

  • True가 기본 값
  • True__repr__ 메서드가 생성됨
  • __repr__ 메서드는 해당 객체가 어떤 객체인지 표현하는 문자열을 반환함
  • 클래스의 이름과 각 필드의 값을 갖음
  • 클래스가 이미 __repr__ 메서드를 정의 했으면 이 매개변수는 무시됨

eq

  • True가 기본 값
  • True__eq__ 메서드가 생성됨
  • __eq__ 메서드는 두 객체가 동일한지 판단해주는 연산 메서드
  • 비교되는 두 인스턴스는 같은 데이터 타입이어야 함
  • 클래스가 이미 __eq__ 메서드를 정의 했으면 이 매개변수는 무시됨

order

  • False가 기본 값
  • True __lt__, __le__, __gt__, __ge__ 메서드가 생성됨
  • 동일한지 판단하는 eq와 달리 객체의 대소를 판단할 때 사용
  • 필드가 튜플인 것처럼 순서대로 비교함
  • 비교되는 두 인스턴스는 같은 데이터 타입이어야 함
  • 인스턴스끼리 sorted를 사용할 수 있어짐
  • 클래스가 이미 __lt__, __le__, __gt__, __ge__ 메서드를 정의 했으면 이 매개변수는 무시됨
from dataclasses import dataclass

@dataclass(order=True)
class Book:
    name: str
    weight: float
    shelf_id: int

b1 = Book('I need Python',1.5,1267)		
b2 = Book('You need Python',0.5,6453)

print(b1>b2)
>>> False		# 'I' < 'Y'

frozen

  • False가 기본 값
  • True면 필드에 새로운 값을 대입하려고 하면 예외를 발생시킴
  • 불변 객체로 만듦
from dataclasses import dataclass

@dataclass(frozen=True)
class Book:
    name: str
    weight: float
    shelf_id: int = 0

test = Book('I need Python',1.5,1267)
test.weight = 2.43
print(test)
>>> Traceback (most recent call last):
  File line 11, in <module>
    test.weight = 2.43
  File "<string>", line 4, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'weight'

unsafe_hash

  • False가 기본 값
  • eqfrozen의 설정에 따라 __hash__ 메서드가 생성됨
  • __hash__ 메서드는 딕셔너리, 집합과 같은 해시 컬렉션에 객체가 추가될 때 사용
  • 인스턴스를 딕셔너리나 집합으로 만들고 싶을 때 사용
  • 인스턴스끼리 중복을 제거할 수 있어짐
from dataclasses import dataclass

@dataclass(unsafe_hash=True)
class Book:
    name: str
    weight: float
    shelf_id: int

b1 = Book('I need Python',1.5,1267)
b2 = Book('You need Python',0.5,6453)
b3 = Book('I need Python',1.5,1267)
b4 = Book('You need Python',0.5,6453)

print(set([b1,b2,b3,b4]))
>>> {Book(name='I need Python', weight=1.5, shelf_id=1267), Book(name='You need Python', weight=0.5, shelf_id=6453)}

필드의 기본 값 설정하기

  • 데이터 클래스는 인스턴스끼리 공유하기 때문에 filed라는 특별한 함수를 사용해 기본 값을 설정해야 함
  • filed 함수의 default, default_factory 옵션에 기본 값으로 설정할 값을 넣으면 됨
from dataclasses import dataclass, field
from typing import List

@dataclass
class Book:
    name: str
    weight: float
    shelf_id: int
    subject: str = field(default='IT')
    author: List[str] = field(default_factory=list)

b1 = Book('I need Python',1.5,1267)

print(b1)
>>> Book(name='I need Python', weight=1.5, shelf_id=1267, subject='IT', author=[])

1개의 댓글

comment-user-thumbnail
2024년 10월 18일

마지막에 filed 오타났어요~

답글 달기