先日Pythonの新機能としてData Classesが採用されました :tada:

Data Classesとは?

PEP 557のなかで、以下のように述べられている。

Data Classes can be thought of as "mutable namedtuples with defaults". Because Data Classes use normal class definition syntax, you are free to use inheritance, metaclasses, docstrings, user-defined methods, class factories, and other Python class features.

一言で言えば、「デフォルト値があるミュータブルなnamedtuple」。

@dataclass
class InventoryItem:
    '''Class for keeping track of an item in inventory.'''
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

のように宣言すると、

def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0) -> None:
    self.name = name
    self.unit_price = unit_price
    self.quantity_on_hand = quantity_on_hand
def __repr__(self):
    return f'InventoryItem(name={self.name!r}, unit_price={self.unit_price!r}, quantity_on_hand={self.quantity_on_hand!r})'
def __eq__(self, other):
    if other.__class__ is self.__class__:
        return (self.name, self.unit_price, self.quantity_on_hand) == (other.name, other.unit_price, other.quantity_on_hand)
    return NotImplemented
def __ne__(self, other):
    if other.__class__ is self.__class__:
        return (self.name, self.unit_price, self.quantity_on_hand) != (other.name, other.unit_price, other.quantity_on_hand)
    return NotImplemented
def __lt__(self, other):
    if other.__class__ is self.__class__:
        return (self.name, self.unit_price, self.quantity_on_hand) < (other.name, other.unit_price, other.quantity_on_hand)
    return NotImplemented
def __le__(self, other):
    if other.__class__ is self.__class__:
        return (self.name, self.unit_price, self.quantity_on_hand) <= (other.name, other.unit_price, other.quantity_on_hand)
    return NotImplemented
def __gt__(self, other):
    if other.__class__ is self.__class__:
        return (self.name, self.unit_price, self.quantity_on_hand) > (other.name, other.unit_price, other.quantity_on_hand)
    return NotImplemented
def __ge__(self, other):
    if other.__class__ is self.__class__:
        return (self.name, self.unit_price, self.quantity_on_hand) >= (other.name, other.unit_price, other.quantity_on_hand)
    return NotImplemented

といったメソッドが自動で生成される。

namedtupleとの違い

  • namedtupleは、偶然同じ数のfieldを持つ他のnamedtupleと比較できる。
    • Data Classでは、ここでFalseを返す。
>>> Point3D(2017, 6, 2) == Date(2017, 6, 2)
True
  • namedtupleは、偶然tupleと比較できる。
    • Data Classでは、ここでFalseを返す
>>> Point2D(1,10)==(1,10)
True
  • fieldを後から追加するのが難しい
  • mutableにできない
  • デフォルト値を指定できない
  • __init____repr__に使われるfiledを制御できない
  • 継承によるfieldの結合ができない

typing.NamedTupleとの違い

  • 型アノテーションを利用できるが、結局はnamedtupleと同じ問題が残る

attrsとの違い

Python 3.7 Release Schedule

予定では2018/6/15がPython3.7のリリース日。
Data Classesは使い勝手が良さそうなので、今から楽しみですね。

PEP 537 -- Python 3.7 Release Schedule | Python.org

Features for 3.7

  • PEP 538, Coercing the legacy C locale to a UTF-8 based locale
  • PEP 539, A New C-API for Thread-Local Storage in CPython
  • PEP 553, Built-in breakpoint()
  • PEP 557, Data Classes
  • PEP 564, Time functions with nanosecond resolution