項目33「サブクラスをメタクラスで検証する」はこう書き換わる
Python 3.6がリリースされた。
Python 3.6で導入された新機能の一つに__init_subclass__
がある。
PEP 487 -- Simpler customisation of class creation | Python.org か石本さんのエントリを参照してほしい。
『Effective Python』の項目33「サブクラスをメタクラスで検証する」ではメタクラスを使ってサブクラスの検証(値の整合性チェックなど)を行うテクニックが解説されている。
多角形のクラスを定義する際に、頂点数が3未満の場合はValueError
を送出する、というサンプルがある。
class ValidatePolygon(type): def __new__(meta, name, bases, class_dict): if bases != (object,): if class_dict["sides"] < 3: raise ValueError("polygons need 3+ sides.") return type.__new__(meta, name, bases, class_dict) class Polygon(object, metaclass=ValidatePolygon): sides = None @classmethod def interior_angles(cls): """内角の総和を求める""" return (cls.sides - 2) * 180 class Triangle(Polygon): sides = 3 if __name__ == '__main__': triangle = Triangle() print(triangle.interior_angles())
Python 3.6では、__init_subclass__
を利用することでメタクラスを使うことなくサブクラスの検証が実現できる。
class Polygon(object): def __init_subclass__(cls, sides, **kwargs): cls.sides = sides if cls.sides < 3: raise ValueError("polygons need 3+ sides.") @classmethod def interior_angles(cls): return (cls.sides - 2) * 180 class Triangle(Polygon, sides=3): pass if __name__ == '__main__': triangle = Triangle() print(triangle.interior_angles())
__init_subclass__
がクラスメソッドである、ということを押さえておけばメタクラスを使う例よりもわかりやすくなっている。
ベストプラクティスを収めた『Effective Python』も時間がたつと変わってしまう、利用している道具の変化は常にを追わないといけない、というのを強く感じる次第である。