何かを書き留める何か

数学や読んだ本について書く何かです。最近は社会人として生き残りの術を学ぶ日々です。

『Effective Python』Item 33: メタクラスを使ってサブクラスの検証をしよう

『Effective Python』の続き。水際で防げ。 www.effectivepython.com

『Effective Python』のChapter 4冒頭に筆者は次のように述べている。

Metaclass are often mentioned in lists of Python's features, but few understand what they accomplish in practice.

『Effective Python』 Chapter 4

Pythonの特徴の1つによくメタクラスが挙げられますが、実際にどう使うのかを理解している人は少ないです。」と訳せるだろうか。*1 そこで筆者はメタクラスの応用例としてサブクラスの検査、登録、注釈を挙げている。 今回のItem 33はサブクラスの検査を取り上げている。

下記の例は、多角形をPythonのクラスで構成する例である。 多角形の厳密な定義は真面目な幾何学の本に任せるとして、頂点が3つ以上であることを検査する機能をメタクラスに織り込んでいる。

class ValidatePolygon(type):
    def __new__(meta, name, bases, class_dict):
        # Don't validate the abstract Polygon class
        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  # Specified by subclasses

    @classmethod
    def interior_angles(cls):
        return (cls.sides - 2) * 180

class Triangle(Polygon):
    sides = 3

ここで、多角形だといっているのに直線を定義しようとして、

class Line(Polygon):
    print('Before sides')
    sides = 1
    print('After sides')

とするときちんとValueErrorが送出される。

*1:accomplishは達成とかそういう意味であるが…