スキップしてメイン コンテンツに移動

dataclassを使う

Pythonの使用歴は、とても長いわけではないが、ほどほどにはプログラムを書いていてそれなりに知っているつもりだった。
が、Python 3.7から重要な変更点としてdataclassというアノテーションが追加されていた点を全く知らなかった。
読んで行くとどうも大抵の場合にはdataclassを使用した方が都合が良いというか、扱いやすく感じるシーンが多いように感じた。

その他にも3.9から入る変更点や、自分の知らないTypingのアノテーションなど。

というわけでサラッと調べたことを振り返ってみる。


データクラス

最近入ったんだろう、そりゃあ見ない顔なわけだ......とか思いたかったがただの自身のキャッチアップ不足。業務で少なくとも2年前から使用している3.7で導入されていた。

雑に使い所と特徴を見ていくと

- @dataclasses.dataclassアノテーションをクラスの頭につけるとデータクラスになる
- __init__を自分で定義しなくてもフィールドプロパティを書いてあげるだけでOK
- dataclass内に関数を定義することはできるし、それ以外にもフィールドの一覧を取得することができたり便利関数が用意されている

という感じ。

ちょっと具体例で見てみる。

これが従来型の例。

class MyClass(object):
   def __init__(self, filename="", changes=0):
       self.filename: str = filename
       self.changes: int = changes


dataclassの場合だとこんな感じ。

import dataclasses


@dataclasses.dataclass
class MyClass:
   self.filename: str = ""
   self.changes: int = 0


JavaでいうところのPOJOのような、データの入れ物として使われることが意図されたもの、が公式的に導入されているということで、これは過去に書いたプログラムにも反映したいと思えるくらいには具合が良さそう。

他にも細かいところだと、内部では__init__処理は呼ばれて、既定したフィールドの値を引数に渡すとそれが代入されるような感じなのだけど、その__init__の処理が終わった後に__post_init__ということで、初期化終了後に呼びたい処理を定義できる。

ここまで用意されていたら何もかもとは言わずともある程度のケースについて対応できることが多いように思えた。すごい。かっこいい。


型の移行

これを読んで少し震えた。

このmypyのドキュメントを読んでいたのは、たまたま扱っているライブラリが返す応答が Mapping[str, str] のような型で、今までDictは数多く使えどMappingというのは使ったことがなかったので、違いを調べようとする過程で見かけたものだった。

結果的にはMappingは以前からあり、Dictのように使えるがRead Onlyを前提としている点が異なるといったところ、なのだろうか。と疑問が渦巻く。

それで、3度読みくらいしてわかったのだけど、3.9からはcollections.abcというところでMappingが既定されることになるようだ。abcはAbstract Base Class。

読んでもやっぱりわからないというか少し靄がかかった状態なので次のあたりも読んでみた。

ダックタイピングで判定、そうするとMappingが持っている振る舞いはdictと同じだから同じとみなせるのかーなるほど、面白い。
初めはListとArrayListの関係、のように捉えればいいかと思っていたけれど仕組みとして違うみたいだし、全然Pythonのことわかっていないんだなというのが改めてわかってしまった......。

ここも読んで雰囲気を掴んでいる。


いくら使い慣れている言語でも、刃を定期的に研がないとあっという間に使えないものになってしまうなあ。