Python | メタクラスの使い方

2021年6月6日

公開日:2021/6/5

Pythonでは,クラスを使うことによってデータと機能を合わせて出力することができる.メタクラスは,クラス変数が適切に定義されているかをチェックするできる.以下にメタクラスの使い方を記す.

◆実施環境

Python 3.8.8

■メタクラスを利用した基本構文

メタクラスの定義方法として,"type"を継承させる方法がある.その後,"__new__"をインスタンスメソッドとして利用する.

# 1の処理
class Meta_test(type): # メタクラス

  def __new__(metacls,cls_name,cls_bases,cls_attrs):
    print(f'metacls:{metacls}') # metaclsはメタクラスのタイプと名前を出力
    print(f'cls_name:{cls_name}') # cls_nameはクラスの名前を出力
    print(f'cls_bases:{cls_bases}') # cls_basesは継承クラスを出力
    print(f'cls_attrs:{cls_attrs}') # cls_attrsはクラスが持つ値や関数を出力

    return super().__new__(metacls,cls_name,cls_bases,cls_attrs)

class Class1(metaclass=Meta_test):
    z = '1234'
    pass

■実行結果

# 1の結果
metacls:<class '__main__.Meta_test'>
cls_name:Class1
cls_bases:()
cls_attrs:{'__module__': '__main__', '__qualname__': 'Class1', 'z': '1234'}

■Exceptionを用いたクラスのチェック

“class 例外クラス(Exception):"によって例外を定義し,特定の変数がない場合にエラーを出力させることができる.以下はエラーが出力される構文と出力されない構文を作成した.

# 1の処理(特定の変数がない場合にエラーが出力)
class MetaExcept(Exception): # 例外を定義する
  pass

class Meta_test(type): # メタクラス

  def __new__(metacls,cls_name,cls_bases,cls_attrs):
    print(f'metacls:{metacls}') # metaclsはメタクラスのタイプと名前を出力
    print(f'cls_name:{cls_name}') # cls_nameはクラスの名前を出力
    print(f'cls_bases:{cls_bases}') # cls_basesは継承クラスを出力
    print(f'cls_attrs:{cls_attrs}') # cls_attrsはクラスが持つ値や関数を出力

    if 'xyz' not in cls_attrs.keys():
      raise MetaExcept('xyzを定義してください')

    return super().__new__(metacls,cls_name,cls_bases,cls_attrs)

class Class1(metaclass=Meta_test):
  z = '1234'
  pass

# 2の処理(#1の処理を受け,特定の変数を記述:エラーなし)
class MetaExcept(Exception):
  pass

class Meta_test(type): # メタクラス

  def __new__(metacls,cls_name,cls_bases,cls_attrs):
    print(f'metacls:{metacls}') # metaclsはメタクラスのタイプと名前を出力
    print(f'cls_name:{cls_name}') # cls_nameはクラスの名前を出力
    print(f'cls_bases:{cls_bases}') # cls_basesは継承クラスを出力
    print(f'cls_attrs:{cls_attrs}') # cls_attrsはクラスが持つ値や関数を出力

    if 'xyz' not in cls_attrs.keys():
      raise MetaExcept('xyzを定義してください')

    return super().__new__(metacls,cls_name,cls_bases,cls_attrs)

class Class1(metaclass=Meta_test):
  z = '1234'
  xyz = 'ABCD'
  pass

■実行結果

# 1の結果(エラーが出力)
metacls:<class '__main__.Meta_test'>
cls_name:Class1
cls_bases:()
cls_attrs:{'__module__': '__main__', '__qualname__': 'Class1', 'z': '1234'} 
__main__.MetaExcept: xyzを定義してください

# 2の結果(エラーが出力されず,'xyz'がcls_attrsに含まれる)
metacls:<class '__main__.Meta_test'>
cls_name:Class1
cls_bases:()
cls_attrs:{'__module__': '__main__', '__qualname__': 'Class1', 'z': '1234', 'xyz': 'ABCD'}

以上