web-dev-qa-db-ja.com

データクラスとは何ですか?また、一般的なクラスとはどう違いますか?

PEP 557 では、データクラスがpython標準ライブラリに導入されます。

それらは@dataclassデコレータを使用し、「デフォルトの可変名前付きタプル」であると想定されていますが、これが実際に何を意味し、どのように一般的なクラスと異なるのかがよくわかりません。

pythonデータクラスとはどのようなもので、いつ使用するのが最適ですか?

64
kingJulian

データクラスは、多くのロジックが含まれているだけでなく、状態の保存を対象とした通常のクラスです。ほとんどが属性で構成されるクラスを作成するたびに、データクラスを作成しました。

dataclassesモジュールが行うことは、データクラスを作成するためにeasierにすることです。それはあなたのためにボイラープレートの多くの世話をします。

これは、データクラスをハッシュ可能にする必要がある場合に特に重要です。これには、__hash__メソッドと__eq__メソッドが必要です。デバッグを容易にするためにカスタム__repr__メソッドを追加すると、非常に冗長になる可能性があります。

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

    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 total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

    def __repr__(self) -> str:
        return (
            'InventoryItem('
            f'name={self.name!r}, unit_price={self.unit_price!r}, '
            f'quantity_on_hand={self.quantity_on_hand!r})'

    def __hash__(self) -> int:
        return hash((self.name, self.unit_price, self.quantity_on_hand))

    def __eq__(self, other) -> bool:
        if not isinstance(other, InventoryItem):
            return NotImplemented
        return (
            (self.name, self.unit_price, self.quantity_on_hand) == 
            (other.name, other.unit_price, other.quantity_on_hand))

dataclassesを使用すると、次のように減らすことができます。

from dataclasses import dataclass

@dataclass(unsafe_hash=True)
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

同じクラスデコレータは、比較メソッド(__lt____gt__など)を生成し、不変性を処理することもできます。

namedtupleクラスもデータクラスですが、デフォルトでは不変です(シーケンスでもあります)。 dataclassesはこの点ではるかに柔軟性があり、 namedtupleクラスと同じ役割を満たす のように簡単に構成できます。

PEPは attrsプロジェクト に触発され、さらに多くのことができます(スロット、バリデーター、コンバーター、メタデータなどを含む)。

いくつかの例をご覧になりたい場合、最近 Advent of Code ソリューションのいくつかにdataclassesを使用しました。 7日目8日目11日目 および 20日目 .

Pythonバージョン<3.7でdataclassesモジュールを使用する場合は、 バックポートモジュール (3.6が必要)をインストールするか、attrsプロジェクトを使用します。上記の通り。

79
Martijn Pieters

概要

質問は解決されました。ただし、この回答では、データクラスの基本的な理解に役立つ実用的な例をいくつか追加しています。

pythonデータクラスとは正確に何で、いつ使用するのが最適ですか?

  1. コードジェネレーター:定型コードを生成します;通常のクラスに特別なメソッドを実装するか、データクラスにそれらを自動的に実装させるかを選択できます。
  2. データコンテナ:データを保持する構造体(タプルや辞書など)、多くの場合、 classes、namedtupleなどのドット付き属性アクセスその他

「デフォルトの[s]を持つ可変名前付きタプル」

後者のフレーズの意味は次のとおりです。

  • mutable:デフォルトでは、データクラス属性を再割り当てできます。オプションでそれらを不変にすることができます(以下の例を参照)。
  • namedtuplenamedtupleまたは通常のクラスのように、ドットで区切られた属性アクセスがあります。
  • default:デフォルト値を属性に割り当てることができます

一般的なクラスと比較して、定型コードの入力を節約できます。


特徴

以下にデータクラス機能の概要を示します(概要表の例を参照)。

あなたが得るもの

以下は、デフォルトでデータクラスから取得する機能です。

属性+表現+比較

import dataclasses


@dataclasses.dataclass
#@dataclasses.dataclass()                                       # alternative
class Color:
    r : int = 0
    g : int = 0
    b : int = 0

次のデフォルトは、Trueに自動的に設定されます。

@dataclasses.dataclass(init=True, repr=True, eq=True)

オンにできるもの

適切なキーワードがTrueに設定されている場合、追加の機能を使用できます。

注文

@dataclasses.dataclass(order=True)
class Color:
    r : int = 0
    g : int = 0
    b : int = 0

< > <= >= と同様に、順序付けメソッドが実装され(演算子のオーバーロード:functools.total_ordering)、同等のテストが強化されました。

ハッシュ可能、ミュータブル

@dataclasses.dataclass(unsafe_hash=True)                        # override base `__hash__`
class Color:
    ...

オブジェクトは潜在的に可変(望ましくない可能性があります)ですが、ハッシュが実装されています。

ハッシュ可能、不変

@dataclasses.dataclass(frozen=True)                                 # `eq=True` (default) to be immutable 
class Color:
    ...

ハッシュが実装され、オブジェクトの変更または属性への割り当てが許可されなくなりました。

全体的に、unsafe_hash=Trueまたはfrozen=Trueの場合、オブジェクトはハッシュ可能です。

元の ハッシュロジックテーブル も参照してください。

あなたが手に入らないもの

次の機能を取得するには、特別なメソッドを手動で実装する必要があります。

アンパック可能

@dataclasses.dataclass
class Color:
    r : int = 0
    g : int = 0
    b : int = 0

    def __iter__(self):
        yield from dataclasses.astuple(self)

最適化

@dataclasses.dataclass
class SlottedColor:
    __slots__ = ["r", "b", "g"]
    r : int
    g : int
    b : int

オブジェクトサイズが縮小されました。

>>> imp sys
>>> sys.getsizeof(Color)
1056
>>> sys.getsizeof(SlottedColor)
888

状況によっては、__slots__は、インスタンスの作成と属性へのアクセスの速度も改善します。また、スロットはデフォルトの割り当てを許可しません。それ以外の場合は、ValueErrorが発生します。

スロットの詳細については、この ブログ投稿 を参照してください。


要約表

+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
|       Feature        |       Keyword        |                      Example                       |           Implement in a Class          |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
| Attributes           |  init                |  Color().r -> 0                                    |  __init__                               |
| Representation       |  repr                |  Color() -> Color(r=0, g=0, b=0)                   |  __repr__                               |
| Comparision*         |  eq                  |  Color() == Color(0, 0, 0) -> True                 |  __eq__                                 |
|                      |                      |                                                    |                                         |
| Order                |  order               |  sorted([Color(0, 50, 0), Color()]) -> ...         |  __lt__, __le__, __gt__, __ge__         |
| Hashable             |  unsafe_hash/frozen  |  {Color(), {Color()}} -> {Color(r=0, g=0, b=0)}    |  __hash__                               |
| Immutable            |  frozen + eq         |  Color().r = 10 -> TypeError                       |  __setattr__, __delattr__               |
|                      |                      |                                                    |                                         |
| Unpackable+          |  -                   |  r, g, b = Color()                                 |   __iter__                              |
| Optimization+        |  -                   |  sys.getsizeof(SlottedColor) -> 888                |  __slots__                              |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+

+これらのメソッドは自動的に生成されず、データクラスに手動で実装する必要があります。

* __ne__実装されていません


追加機能

初期化後

@dataclasses.dataclass
class RGBA:
    r : int = 0
    g : int = 0
    b : int = 0
    a : float = 1.0

    def __post_init__(self):
        self.a : int =  int(self.a * 255)


RGBA(127, 0, 255, 0.5)
# RGBA(r=127, g=0, b=255, a=127)

継承

@dataclasses.dataclass
class RGBA(Color):
    a : int = 0

変換

データクラスをタプルまたは辞書に変換、 再帰的に

>>> dataclasses.astuple(Color(128, 0, 255))
(128, 0, 255)
>>> dataclasses.asdict(Color(128, 0, 255))
{r: 128, g: 0, b: 255}

制限事項


参照資料

  • R. Hettinger's talk onDataclasses:すべてのコードジェネレーターを終了するコードジェネレーター
  • T. Hunnerの talk onEaser Classes:Python Classes Without All Cruft
  • ハッシュの詳細に関するPythonの documentation
  • Real Python's guide onThe Ultimate Guide to Data Classes in Python 3.7
  • A. Shawの ブログ投稿 onPython 3.7データクラスの簡単なツアー
  • E.スミスの githubリポジトリ ondataclasses
21
pylang

ところでRaymond Hettinger(Pythonコア開発者)は、PyCon 2018で素晴らしい講演を行いました。

https://www.youtube.com/watch?v=T-TwcmT6Rcw&t=139

スライドはこちら: https://Twitter.com/raymondh/status/995693882812915712

comparison

13
Messa

PEP仕様 から:

PEP 526「変数アノテーションの構文」で定義されているタイプアノテーションを持つ変数のクラス定義を検査するクラスデコレーターが提供されます。このドキュメントでは、そのような変数はフィールドと呼ばれます。これらのフィールドを使用して、デコレーターは生成されたメソッド定義をクラスに追加して、インスタンスの初期化、repr、比較メソッド、およびオプションで仕様セクションで説明されている他のメソッドをサポートします。このようなクラスはデータクラスと呼ばれますが、実際にはクラスには特別なものはありません。デコレータは生成されたメソッドをクラスに追加し、与えられた同じクラスを返します。

@dataclassジェネレーターは、そうでなければ__repr____init____lt__、および__gt__のように自分で定義するクラスにメソッドを追加します。

2
Mahmoud Hossam

この単純なクラスFooを考えてください

from dataclasses import dataclass
@dataclass
class Foo:    
    def bar():
        pass  

dir()組み込みの比較は次のとおりです。左側には@dataclassデコレータのないFooがあり、右側には@dataclassデコレータのあるものがあります。

enter image description here

比較のためにinspectモジュールを使用した後の別の差分があります。

enter image description here

0
prosti