Categories: Python

【Python】メタクラスって結局なんなの?

この記事では、Pythonのメタクラスについて解説します。

この記事を読んで学べること

  • メタクラスとは
  • メタクラスの使い方
  • メタクラスでできること

メタクラスとは?

メタクラスとは「クラスを生成するクラスのこと」です。 Pythonではメタクラスであるtype()を使うことで動的にクラスを生成することができます。

type()は引数が1つの場合に型を返し、引数が3つの場合にメタクラスとして動作します。

class type(object)
class type(name, bases, dict, **kwds)

実際にtype()を使ってクラスを定義してみます。以下のコードのクラスは同等です。

# 通常のクラス定義
class Demo:
    def __init__(self):
        print('demo')

Demo()  # demo


# type() を使ったクラス定義
def __init__(self):
    print('demo')

Demo = type('Demo', (), {'__init__': __init__})
Demo()  # demo

type()を使って動的にクラスを定義することができました。このようにメタクラスとはクラスを生成するクラスのことを言います。

メタクラスの変更

メタクラスは以下のように指定できる。

class Demo(metaclass=メタクラス):
    ...

デフォルトは以下のようになっている。

class Demo(metaclass=type):
    ...

メタクラスは子クラスにも適用されます。

class Demo(metaclass=メタクラス):
    ...

# このクラスもメタクラスで生成される
class Child(Demo):
    ...

メタクラスの定義

メタクラスは自分で定義することができます。簡単な例としてコンストラクタだけを定義したメタクラスを適当なクラスに適用してみます。

# メタクラス
class MyMeta:
    def __init__(cls, name, bases, attrs):
        print('MyMeta init')


# 空のクラスにメタクラスを指定
class MyClass(metaclass=MyMeta):
    pass

実行結果

MyMeta init

__init__()でクラス変数を追加することもできる。

class MyMeta(type):
    def __init__(cls, name, bases, attrs):
        cls.attr = '属性'

class MyClass(metaclass=MyMeta):
    pass

print(MyClass.attr)
# 属性

__call__()を使うことでインスタンスに属性を追加することもできます。

class MyMeta(type):

    def __call__(cls, *args, **kwds):
        obj = super().__call__(*args, **kwds)
        obj.instance = 'インスタンス変数'
        return obj

class MyClass(metaclass=MyMeta):
    pass

m = MyClass()
print(m.instance)
# インスタンス変数

メタクラスでできること

メタクラスを使うことでクラスの定義が完了する前にクラスの属性やメソッドを自動的に変更・追加することができます。基本的には__new__()__init__()と同じような実装が考えられるが、これらのメソッドではできないことを補うのが主な使い方になります。

また、__new__()などで実装できるけど色々なクラスに適用させたい場合もメタクラスで定義すると楽できるかも。以下のコードは、メタクラスを使ってシングルトンを実装した例です。

class SingletonMetaClass(type):
    def __init__(cls, name, bases, attrs):
        cls._instance = None

    def __call__(cls, *args, **kwds):
        if cls._instance is None:
            cls._instance = super().__call__(*args, **kwds)
        return cls._instance


class Singleton(metaclass=SingletonMetaClass):
    pass


a = Singleton()
b = Singleton()

print(a is b)
# True

このように、メタクラスを適用するだけでシングルトンを実装することができる。

まとめ

この記事では、Pyhtonのメタクラスについて解説しました。

メタクラスは、フレームワークやライブラリの開発、特定のプログラミングパターンの実装など高度な場面でよく使われます。あまり使う機能ではないので無理に覚えておく必要もありません。

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ

ゆうまる

独学でプログラミングを勉強しているおじさん。いろんな言語を勉強したが浅く広くなためあまり仕事につながらない。また忘れっぽいため自分のブログを備忘録としても使っている。産まれてこのかたずっとネコを飼ってる生粋のネコ派。最近お腹が出てきて筋トレに奮闘中!

Recent Posts

【Dart】コンストラクタのデフォルト引数について

Dartのコンストラクタのデフォルト引数…

2週間 ago

【Unity】有料アセットを無料で手に入れる方法

この記事では、Unityの有料アセットを…

4か月 ago

【Python】任意の秒数だけ処理を一時停止する方法【sleep()関数】

この記事では、Pythonで任意の秒数だ…

1年 ago

【Python】Wordの文書の新規作成と読み書き

この記事では、Pythonを使ってWor…

1年 ago

【Unity】割合から数値に数値から割合に変換する

この記事では、割合から数値に変換する関数…

1年 ago