python2 python3両方に対応できるmetaclassの書き方

  • 14
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

python2.xとpython3.xでmetaclassを利用する構文が異なっている。
一方でひとつのファイルで両方のバージョンをサポートしたいことがある。
そのような場合の書き方について。

metaclass(HasVersion)

以下のようなmetaclass HasVersionMetaがある。
単にversion番号のような文字列を持っているというだけのmetaclass。

class HasVersionMeta(type):
    def __new__(cls, name, bases, attrs):
        attrs["version"] = "0.0.1"
        return super(HasVersionMeta, cls).__new__(cls, name, bases, attrs)

これを使ったclassを定義したい。

python3の場合

python3の場合は継承の際に渡す引数の箇所にmetaclassオプションを付ける。

class A(object, metaclass=HasVersionMeta):
    pass

python2の場合

python2の場合は、metaclassという特別な名前のhookに代入する

class A(object):
    __metaclass__ = HasVersionMeta

両方に対応する場合

metaclassとして使われるクラスはcallable objectでもあり。
親classになるtype()が動的にclassを生成される際に使われることを考えると同じ機能をもっているはず。
なので以下のように書けば良い。

HasVersion = HasVersionMeta("A", (object, ), {"__doc__": HasVersionMeta.__doc__})


class A(HasVersion):
    pass

動作する。

print(A.version)
# 0.0.1