dataclass

Published by onesixx on

https://youtu.be/CvQ7e6yUtnw

import random
import string

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

#generate_id()

class Person:
    def __init__(self, name:str, address:str):
        self.name = name
        self.address = address

def main() -> None:
    person = Person(name="john", address="yatop-ro 162")
    print(person)

if __name__ == "__main__":
    main()

ν™œμš©μ΄ μ–΄λ ΅λ‹€. Person의 nameμ΄λ‚˜ addressr

 $ conda run -n notidash --no-capture-output --live-stream python /Users/onesixx/my/git/noti-api/examtest/dataclass_ex.py
<__main__.Person object at 0x7f8861d3cf10>
class Person:
    def __init__(self, name:str, address:str):
        self.name = name
        self.address = address
    def __str__(self) -> str:
        return f"{self.name}, {self.address}"
 john, yatop-ro 162
import random
import string
from dataclasses import dataclass

def generate_id() -> str:
    return "".join(random.choices(string.ascii_uppercase, k=12))
@dataclass
class Person:
    name:str
    address:str

def main() -> None:
    person = Person(name="john", address="yatop-ro 162")
    print(person)

if __name__ == "__main__":
    main()
Person(name='john', address='yatop-ro 162')

dataclass라ㄴ

https://sjquant.tistory.com/30

파이썬 3.7λΆ€ν„° λ„μž…λœ dataclasses에 λŒ€ν•΄ μ•Œμ•„λ³΄μž

from dataclasses import dataclass, field

...(μƒλž΅)

@dataclass
class Client:
    interface: websockets.server.WebSocketServerProtocol = field(repr=False)
    sid: str = field(default_factory=partial(generate_code, 36))

    ...(μƒλž΅)
  • 파이썬 3.7λΆ€ν„° ν‘œμ€€ 라이브러리둜 λ“±μž¬
  • μ΄λŠ” λ°μ΄ν„° 클래슀λ₯Ό 보닀 μš©μ΄ν•˜κ²Œ μ„ μ–Έν•΄μ£ΌλŠ” λ°μ½”λ ˆμ΄ν„°
  • Type Annotation을 지원.
  • ν΄λž˜μŠ€μ— @dataclass λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜λ©΄ __int____repr____eq__ λ“±μ˜ λ©”μ†Œλ“œλ₯Ό μžλ™μœΌλ‘œ μ •μ˜ν•΄ μ€€λ‹€.
from dataclasses import dataclass

# μ΄λ ‡κ²Œ @dataclass λ°μ½”λ ˆμ΄ν„°λ₯Ό 클래슀 μœ„μ— λΆ™μ—¬μ€€λ‹€.
@dataclass
class Item:
    id: int
    name: str


print(Item(1, "Apple"))
print(Item(2, "Banana"))

μ‹€ν–‰κ²°κ³Ό

Item(id=1, name='Apple')
Item(id=2, name='Banana')
  • μœ„μ˜ μ½”λ“œ 같은 경우 λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ __init__λ©”μ†Œλ“œμ— id와 name을 λ³€μˆ˜λ‘œ λ°›λŠ” 것이 μ—†κΈ° λ•Œλ¬Έμ— μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.
  • λ§Œμ•½ __init__λ©”μ†Œλ“œλ₯Ό μ •μ˜ν–ˆλ‹€ν•˜λ”λΌλ„, __repr__λ©”μ†Œλ“œκ°€ μ •μ˜λ˜μ–΄ μžˆμ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μ•„λž˜μ™€ 같이 좜λ ₯λœλ‹€.
class Item:
    id: int
    name: str

    def __init__(self, id: int, name: str):
        self.id = id
        self.name = name


print(Item(1, "Apple"))
print(Item(2, "Banana"))
class Item:
    id: int
    name: str

    def __init__(self, id: int, name: str):
        self.id = id
        self.name = name


print(Item(1, "Apple"))
print(Item(2, "Banana"))

μ‹€ν–‰κ²°κ³Ό

>>
<__main__.Item object at 0x7fd501796898>
<__main__.Item object at 0x7fd501796898
  • 데이터λ₯Ό μ •μ˜ν•˜λŠ” ν΄λž˜μŠ€λΌλŠ” μ μ—μ„œ κΈ°μ‘΄ 파이썬의 collections.namedtuple λΉ„μŠ·ν•˜λ‹€. ν•˜μ§€λ§Œ,@dataclassλ₯Ό μ‚¬μš©ν•œ ν΄λž˜μŠ€λŠ” 말 κ·ΈλŒ€λ‘œ ν΄λž˜μŠ€λΌλŠ” μ μ—μ„œ λ©”μ†Œλ“œλ‚˜ ν”„λ‘œνΌν‹°λ₯Ό μΆ”κ°€ν•  수 μžˆλ‹€.
  • dataclasses.fieldλ₯Ό μ‚¬μš©ν•˜λ©΄ ν•΄λ‹Ή ν”„λ‘œνΌν‹°μ— λŒ€ν•œ 섀정을 해쀄 수 μžˆλ‹€. (ex: default_factoryreprμ—¬λΆ€)
from dataclasses import dataclass, field
from functools import partial
import uuid


@dataclass
class Factory:
    id = field(default_factory=partial(uuid.uuid4))
    items = field(default_factory=list)


f1 = Factory()
print(f1.items)
f1.items += ['apple', 'banana']
print(f1.items)
print(f1)

μ‹€ν–‰κ²°κ³Ό

[]
['apple', 'banana']
Factory(id=UUID('990091ef-6058-4754-b1f5-78e3546cc7bd'), items=['apple', 'banana'])
  • 파이썬의 Type Annotation을 ν™œμš©ν•˜κΈ΄ν•˜μ§€λ§Œ, ν•΄λ‹Ή νƒ€μž…μ΄ λ§žλŠ”μ§€ κ²€μ¦(validate)ν•˜μ§€λŠ” μ•ŠλŠ”λ‹€.
  • λ§Œμ•½ dataclassesλ₯Ό μ‚¬μš©ν•˜κ³  κ²€μ¦κΉŒμ§€ μ›ν•œλ‹€λ©΄ pydantic의 pydantic.dataclassesλ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€. (pydantic λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 좔후에 μ œλŒ€λ‘œ κ³΅λΆ€ν•΄μ„œ μ •λ¦¬ν•˜κ² λ‹€.) [μ°Έκ³ ]

ex

from dataclasses import dataclass, asdict
from os          import path, environ

base_dir =path.dirname(path.abspath(__file__))
# λ°μ½”λ ˆμ΄λ”λ₯Ό ν™œμš©ν•΄ λ°μ΄ν„°ν΄λž˜μŠ€ λ§Œλ“€κΈ°
@dataclass
class mainConfig():
    BASE_DIR:str = base_dir

# 상속
@dataclass
class localConfig(mainConfig):
    HOST:str = '127.0.0.1'
    PORT:int = 8085
    DEBUG:bool = True
    DEV_TOOLS_PROPS_CHECK:bool = True

print(mainConfig())
# mainConfig(BASE_DIR='/Users/onesixx/my/git/dash-adminlte')
localConfig()
#localConfig(BASE_DIR='/Users/onesixx/my/git/dash-adminlte', 
# HOST='127.0.0.1', PORT=8085, DEBUG=True, DEV_TOOLS_PROPS_CHECK=True)
localConfig().PORT
#808
# κ°μ²΄λŠ” unpacking이 μ•ˆλ˜κΈ° λ•Œλ¬Έμ— asdict()μ‚¬μš©ν•˜μ—¬ dictionary둜 λ³€κ²½
asdict(localConfig())
# {'BASE_DIR': '/Users/onesixx/my/git/dash-adminlte',
#  'HOST': '127.0.0.1',
#  'PORT': 8085,
#  'DEBUG': True,
#  'DEV_TOOLS_PROPS_CHECK': True}


def ufunc_test(PORT=None, DEBUG=None, **kwargs):
    print(PORT, DEBUG)

ufunc_test(localConfig())
ufunc_test(asdict(localConfig()))
#localConfig(BASE_DIR='/Users/onesixx/my/git/dash-adminlte', 
# HOST='127.0.0.1', PORT=8085, DEBUG=True, DEV_TOOLS_PROPS_CHECK=True) None
# PORTκ°€ localConfig()이라고 μƒκ°ν•˜κ³ , DEBUGλŠ” μ—†μœΌλ‹ˆ None
ufunc_test(**asdict(localConfig()))
#8085 True

cofig

MENU_ITEMS = ("home", "basiccard", "socialcard", "tabcard",)
menu = [(f"{menu}", f"/{menu}") for menu in MENU_ITEMS]
print(menu)
# [('home',       '/home'),
#  ('basiccard',  '/basiccard'),
#  ('socialcard', '/socialcard'),
#  ('tabcard',    '/tabcard')]

idx=MENU_ITEMS.index("basiccard")
#1
menu[idx]
#('basiccard', '/basiccard')
menu[idx][0]
#'basiccard'
menu[idx][1]
#'/basiccard'

dataclasses λͺ¨λ“ˆ μ‚¬μš©λ²•

https://www.daleseo.com/python-dataclasses/

μš°λ¦¬λŠ” 파이썬으둜 코딩을 ν•˜λ©΄μ„œ 데이터λ₯Ό 담아두기 μœ„ν•΄μ„œ μ—¬λŸ¬κ°€μ§€ 방법을 μ‚¬μš©ν•©λ‹ˆλ‹€.

리슀트(list), νŠœν”Œ(tuple), 사전(dictoinary), λ„€μž„λ“œ νŠœν”Œ(namedtuple), μ„ΈνŠΈ(set), ν”„λ‘œμ¦Œ μ„ΈνŠΈ(frozen set)와 같은 λ‚΄μž₯ 자료 κ΅¬μ‘°λŠ” μ‚¬μš©ν•˜κΈ° κ°„νŽΈν•˜λ‹€λŠ” μž₯점이 μžˆμŠ΅λ‹ˆλ‹€.

λ°˜λ©΄μ— 클래슀(class)λ₯Ό μ΄μš©ν•΄μ„œ 데이터λ₯Ό 담아두면 type-safe해지기 λ•Œλ¬Έμ— ν”„λ‘œκ·Έλž¨ μ‹€ν–‰ 쀑에 였λ₯˜κ°€ λ°œμƒν•  ν™•λ₯ μ΄ μ μ–΄μ§„λ‹€λŠ” μž₯점이 μžˆμŠ΅λ‹ˆλ‹€.

파이썬 3.7μ—μ„œ dataclassesλΌλŠ” 맀우 맀λ ₯적인 λͺ¨λ“ˆμ΄ ν‘œμ€€ λΌμ΄λΈŒλŸ¬λ¦¬μ— μΆ”κ°€λ˜μ—ˆλŠ”λ°μš”.
이번 ν¬μŠ€νŒ…μ—μ„œλŠ” λ‚΄μž₯ 자료 ꡬ쑰처럼 νŽΈλ¦¬ν•˜λ©΄μ„œλ„ 클래슀처럼 κ²¬κ³ ν•œ 데이터 ν΄λž˜μŠ€μ— λŒ€ν•΄μ„œ μ•Œμ•„λ³΄λ„λ‘ ν•˜κ² μŠ΅λ‹ˆλ‹€.

κΈ°μ‘΄ λ°©μ‹μ˜ 클래슀 μž‘μ„±ν•˜κΈ°

λ¨Όμ € dataclasses λͺ¨λ“ˆμ—†μ΄, μš°λ¦¬λŠ” μ–΄λ–»κ²Œ 데이터λ₯Ό 담아두기 μœ„ν•œ 클래슀λ₯Ό μž‘μ„±ν•˜μ˜€λŠ”μ§€ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.
예λ₯Ό λ“€μ–΄, μ‚¬μš©μž 데이터λ₯Ό 담아두기 μœ„ν•œ User ν΄λž˜μŠ€λ₯Ό μž‘μ„±ν•œλ‹€κ³  κ°€μ •ν•˜λ €λ©΄ λ‹€μŒκ³Ό 같은 μ½”λ“œκ°€ ν•„μš”ν•  κ²ƒμž…λ‹ˆλ‹€.

from datetime import date


class User:
    def __init__(self, id: int, name: str, birthdate: date, admin: bool = False) -> None:
        self.id = id
        self.name = name
        self.birthdate = birthdate
        self.admin = admin

        
>>> user = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user
<__main__.User object at 0x105558100>


>>> user1 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user2 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user1 == user2
False

μœ„ μ½”λ“œλ₯Ό 잘 μ‚΄νŽ΄λ³΄λ©΄ λ³΄μΌλŸ¬ ν”Œλ ˆμ΄νŠΈ(boiler-plate)κ°€ λˆˆμ— λˆλ‹€.
idnamebirthdateadmin κ° λ³€μˆ˜κ°€ 3λ²ˆμ”© λ°˜λ³΅λ˜λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€. ?

μœ„ 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό 좜λ ₯해보면 좜λ ₯ 결과에 ν•„λ“œκ°’μ΄ λ‚˜νƒ€λ‚˜μ§€ μ•Šμ•„μ„œ λΆˆνŽΈν•©λ‹ˆλ‹€.

μ΄λ²ˆμ—λŠ” 이 클래슀둜 μƒμ„±ν•œ 두 개의 μΈμŠ€ν„΄μŠ€λ₯Ό 동등성(equality)을 μ²΄ν¬ν•΄λ³ΌκΉŒμš”?

__repr__() λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•˜μ—¬ ν•„λ“œκ°’μ΄ λͺ¨λ‘ 좜λ ₯λ˜λ„λ‘ μΈμŠ€ν„΄μŠ€μ˜ 좜λ ₯ ν˜•νƒœλ₯Ό 바꿔보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.

from datetime import date


class User:
    def __init__(
        self, id: int, name: str, birthdate: date, admin: bool = False
    ) -> None:
        self.id = id
        self.name = name
        self.birthdate = birthdate
        self.admin = admin

    def __repr__(self):
        return (
            self.__class__.__qualname__ + f"(id={self.id!r}, name={self.name!r}, "
            f"birthdate={self.birthdate!r}, admin={self.admin!r})"
        )

    
>>> user1 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user1
User(id=1, name='Steve Jobs', birthdate=datetime.date(1955, 2, 24), admin=False)

두 개의 μΈμŠ€ν„΄μŠ€ 간에 ν•„λ“œμ˜ 값이 λͺ¨λ‘ 같을 λ•Œ, λ™λ“±ν•œ μΈμŠ€ν„΄μŠ€λ‘œ μ·¨κΈ‰ν•˜κ³  μ‹Άλ‹€λ©΄ __eq__() λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•΄μ€˜μ•Ό ν•©λ‹ˆλ‹€.

from datetime import date


class User:
    def __init__(
        self, id: int, name: str, birthdate: date, admin: bool = False
    ) -> None:
        self.id = id
        self.name = name
        self.birthdate = birthdate
        self.admin = admin

    def __repr__(self):
        return (
            self.__class__.__qualname__ + f"(id={self.id!r}, name={self.name!r}, "
            f"birthdate={self.birthdate!r}, admin={self.admin!r})"
        )

    def __eq__(self, other):
        if other.__class__ is self.__class__:
            return (self.id, self.name, self.birthdate, self.admin) == (
                other.id,
                other.name,
                other.birthdate,
                other.admin,
            )
        return NotImplemented
    
>>> user1 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user2 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user1 == user2
True

μœ„μ™€ 같이 μ΄μƒμ μœΌλ‘œ μž‘λ™ν•˜λŠ” 클래슀λ₯Ό μž‘μ„±ν•˜λ €λ©΄ μƒκ°ν–ˆλ˜ 것 보닀 λ§Žμ€ μ–‘μ˜ μ½”λ“œκ°€ ν•„μš”ν•˜λ‹€λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.
μ΄λŸ¬ν•œ 보일러 ν”Œλ ˆμ΄νŠΈ μ½”λ“œλ₯Ό 일일이 직접 μž‘μ„±ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€λ©΄ μ–Όλ§ˆλ‚˜ μ’‹μ„κΉŒμš”?

데이터 클래슀의 κΈ°λ³Έ κΈ°λŠ₯ (μž‘μ„±ν•˜κΈ°)

dataclasses λͺ¨λ“ˆμ€ μœ„μ™€ 같이 데이터λ₯Ό 담아두기 μœ„ν•œ 클래슀λ₯Ό 맀우 적은 μ–‘μ˜ μ½”λ“œλ‘œ μž‘μ„±ν•˜κ²Œ ν•΄μ€λ‹ˆλ‹€.
μœ„ 예제 μ½”λ“œλ₯Ό μ΄λ²ˆμ—λŠ” dataclasses λͺ¨λ“ˆμ„ μ΄μš©ν•΄μ„œ μž¬μž‘μ„± ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

from dataclasses import dataclass
from datetime import date

@dataclass
class User:
    id: int
    name: str
    birthdate: date
    admin: bool = False

>>> user1 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user1
User(id=1, name='Steve Jobs', birthdate=datetime.date(1955, 2, 24), admin=False)
>>> user2 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user1 == user2
True

μ–΄λ–€κ°€μš”? λ„ˆλ¬΄ κ°„λ‹¨ν•˜μ§€ μ•Šμ€κ°€μš”? ?

dataclasses λͺ¨λ“ˆμ—μ„œ μ œκ³΅ν•˜λŠ” @dataclass λ°μ½”λ ˆμ΄ν„°λ₯Ό 일반 ν΄λž˜μŠ€μ— μ„ μ–Έν•΄μ£Όλ©΄ ν•΄λ‹Ή ν΄λž˜μŠ€λŠ” μ†Œμœ„ λ°μ΄ν„° ν΄λž˜μŠ€κ°€ λ©λ‹ˆλ‹€.

데이터 ν΄λž˜μŠ€λŠ” __init__()__repr__()__eq__()와 같은 λ©”μ„œλ“œλ₯Ό μžλ™μœΌλ‘œ μƒμ„±ν•΄μ€λ‹ˆλ‹€.
λ”°λΌμ„œ 이 데이터 ν΄λž˜μŠ€λŠ” λ‹€μŒκ³Ό 같이 이전 μ„Ήμ…˜μ—μ„œ μ†μˆ˜ μž‘μ„±ν–ˆλ˜ ν΄λž˜μŠ€μ™€ λ™μΌν•˜κ²Œ μž‘λ™ν•˜λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

자, μ§€κΈˆκΉŒμ§€ 데이터 클래슀의 κΈ°λ³Έ κΈ°λŠ₯을 μ‚΄νŽ΄λ΄€μœΌλ‹ˆ,
μ§€κΈˆλΆ€ν„° 데이터 ν΄λž˜μŠ€κ°€ μ œκ³΅ν•˜λŠ” λ”μš± κ°•λ ₯ν•œ λΆ€κ°€ κΈ°λŠ₯듀에 λŒ€ν•΄μ„œ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

데이터 클래슀의 λΆ€κ°€ κΈ°λŠ₯

λΆˆλ³€ 데이터 λ§Œλ“€κΈ°

기본적으둜 데이터 ν΄λž˜μŠ€λŠ” λ‹΄κ³ μžˆλŠ” 데이터λ₯Ό 자유 자재둜 λ³€κ²½ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

>>> user1 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user1
User(id=1, name='Steve Jobs', birthdate=datetime.date(1955, 2, 24), admin=False)

>>> user1.admin = True
>>> user1
User(id=1, name='Steve Jobs', birthdate=datetime.date(1955, 2, 24), admin=True)

λ§Œμ•½μ— λ°μ΄ν„°μ˜ λΆˆλ³€μ„±(immutability)κ°€ 보μž₯λ˜μ–΄μ•Ό ν•˜λŠ” 경우라면 λ‹€μŒκ³Ό 같이 frozen μ˜΅μ…˜μ„ μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.

from dataclasses import dataclass
from datetime import date

@dataclass(frozen=True)
class User:
    id: int
    name: str
    birthdate: date
    admin: bool = False

### 데이터 ν΄λž˜μŠ€κ°€ λ‹΄κ³  μžˆλŠ” 데이터λ₯Ό 변경해보렀고 ν•˜λ©΄ μ˜ˆμ™Έκ°€ λ°œμƒν•˜λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

>>> user1.admin = True
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 4, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'admin'       

데이터 λŒ€μ†ŒλΉ„κ΅ 및 μ •λ ¬

데이터 클래슀의 μΈμŠ€ν„΄μŠ€ 간에 λŒ€μ†ŒλΉ„κ΅λ₯Ό ν•˜λ €κ³  ν•˜λ©΄ λ‹€μŒκ³Ό 같이 μ˜ˆμ™Έκ°€ λ°œμƒν•©λ‹ˆλ‹€.

>>> user1 < user2
Traceback (most recent call last):
  File "", line 1, in 
TypeError: '<' not supported between instances of 'User' and 'User'

ν•„λ“œκ°’μ— λ”°λΌμ„œ λ°μ΄ν„°μ˜ λŒ€μ†ŒλΉ„κ΅κ°€ ν•„μš”ν•œ 경우라면 order μ˜΅μ…˜μ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

이제 데이터 클래슀 간에 λŒ€μ†ŒλΉ„κ΅κ°€ κ°€λŠ₯ν•˜κ³ , λ”°λΌμ„œ 데이터 정렬도 κ°€λŠ₯ν•΄μ‘ŒμŠ΅λ‹ˆλ‹€.

from dataclasses import dataclass
from datetime import date


@dataclass(order=True)
class User:
    id: int
    name: str
    birthdate: date
    admin: bool = False


>>> user1 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user2 = User(id=2, name="Bill Gates", birthdate=date(1955, 10, 28))
>>> user1 < user2
True
>>> user1 > user2
False

>>> sorted([user2, user1])
[User(id=1, name='Steve Jobs', birthdate=datetime.date(1955, 2, 24), admin=False),
 User(id=2, name='Bill Gates', birthdate=datetime.date(1955, 10, 28), admin=False)]

μ„ΈνŠΈλ‚˜ μ‚¬μ „μ—μ„œ μ‚¬μš©ν•˜κΈ°

데이터 클래슀의 μΈμŠ€ν„΄μŠ€λŠ” 기본적으둜 hashableν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ—,
μ„ΈνŠΈ(set)의 κ°’μ΄λ‚˜ 사전(dictionary)의 ν‚€λ‘œ μ‚¬μš©μ„ ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

>>> set([user1, user2])
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unhashable type: 'User'
        
        

데이터 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό hashableν•˜κ²Œ λ§Œλ“€κ³  μ‹Άλ‹€λ©΄, unsafe_hash μ˜΅μ…˜μ„ μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.

이제 μ„ΈνŠΈλ₯Ό μ΄μš©ν•΄μ„œ 쀑볡 데이터λ₯Ό μ œκ±°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

from dataclasses import dataclass
from datetime import date


@dataclass(unsafe_hash=True)
class User:
    id: int
    name: str
    birthdate: date
    admin: bool = False

>>> user1 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user2 = User(id=2, name="Bill Gates", birthdate=date(1955, 10, 28))
>>> user3 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user4 = User(id=2, name="Bixll Gates", birthdate=date(1955, 10, 28))

>>> set([user1, user2, user3, user4])
{User(id=2, name='Bill Gates', birthdate=datetime.date(1955, 10, 28), admin=False), 
 User(id=1, name='Steve Jobs', birthdate=datetime.date(1955, 2, 24), admin=False)}

데이터 클래슀 μ‚¬μš© μ‹œ μ£Όμ˜μ‚¬ν•­

데이터 클래슀λ₯Ό μ‚¬μš©ν•  λ•Œ ν”νžˆ λ‚˜μ˜€λŠ” μ‹€μˆ˜λŠ”
list와 같은 κ°€λ³€ 데이터 νƒ€μž…μ˜ ν•„λ“œμ— 기본값을 할당해쀄 λ•Œ λ°œμƒν•©λ‹ˆλ‹€.

ν•„λ“œμ˜ 기본값은 μΈμŠ€ν„΄μŠ€ 간에 κ³΅μœ κ°€ 되기 λ•Œλ¬Έμ— 이런 μ‹μœΌλ‘œ κΈ°λ³Έκ°’ 할당이 ν—ˆμš©λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

from dataclasses import dataclass
from datetime import date
from typing import List


@dataclass(unsafe_hash=True)
class User:
    id: int
    name: str
    birthdate: date
    admin: bool = False
    friends: List[int] = []
        
        
ValueError: mutable default  for field friends is not allowed: use default_factory

이럴 λ•ŒλŠ” dataclasses λͺ¨λ“ˆμ—μ„œ μ œκ³΅ν•˜λŠ” filed ν•¨μˆ˜μ˜ default_factory μ˜΅μ…˜μ„ μ‚¬μš©ν•΄μ„œ 맀번 μƒˆλ‘œμš΄ λ¦¬μŠ€νŠΈκ°€ 생성될 수 μžˆλ„λ‘ ν•΄μ€˜μ•Ό ν•©λ‹ˆλ‹€.

from dataclasses import dataclass, field
from datetime import date
from typing import List


@dataclass(unsafe_hash=True)
class User:
    id: int
    name: str
    birthdate: date
    admin: bool = False
    friends: List[int] = field(default_factory=list)
        
>>> user1 = User(id=1, name="Steve Jobs", birthdate=date(1955, 2, 24))
>>> user1.friends
[]
>>> user1.friends.append(2)
>>> user1.friends
[2]

λ§ˆμΉ˜λ©΄μ„œ

μ§€κΈˆκΉŒμ§€ 파이썬의 dataclasses λ‚΄μž₯ λͺ¨λ“ˆμ„ μ΄μš©ν•΄μ„œ 데이터 클래슀λ₯Ό μ–΄λ–»κ²Œ μž‘μ„±ν•˜κ³  μ‚¬μš©ν•˜λŠ”μ§€ μ•Œμ•„λ³΄μ•˜μŠ΅λ‹ˆλ‹€.
데이터 클래슀λ₯Ό 잘 ν™œμš©ν•˜μ…”μ„œ 보일러 ν”Œλ ˆμ΄νŠΈ μ½”λ“œλ₯Ό μž‘μ„±ν•  μ‹œκ°„μ„ 아끼고, κ·Έ μ‹œκ°„μ— μ’€ 더 λΉ„μ§€λ‹ˆμŠ€μ— μ˜λ―ΈμžˆλŠ” μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ‹€ 수 μžˆμœΌμ…¨μœΌλ©΄ μ’‹κ² μŠ΅λ‹ˆλ‹€.

파이썬의 dataclasses λ‚΄μž₯ λͺ¨λ“ˆμ— λŒ€ν•œ 더 μžμ„Έν•œ λ‚΄μš©μ€ dataclasses - Data Classes - Python 3.8.2 documentation을 μ°Έκ³  λ°”λΌκ² μŠ΅λ‹ˆλ‹€.
dataclasses λͺ¨λ“ˆμ΄ λ§ˆμŒμ— λ“œμ…¨λ‹€λ©΄ 이보닀 μ’€ 더 κ°•λ ₯ν•œ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” attrsμ΄λΌλŠ” νŒ¨ν‚€μ§€λ„ μžˆμœΌλ‹ˆ μ°Έκ³ λ°”λΌκ² μŠ΅λ‹ˆλ‹€.

Categories: Python Basic

onesixx

Blog Owner

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x