この記事では、Pythonで型を動的に生成する方法を解説します。
動的に型生成することでメタプログラミングをすることができます。具体的には、クラスの生成プロセスをカスタマイズすることができます。
それでは、型の生成方法を見ていきましょう!
動的に型を生成する方法
動的に型を生成するには、type()
関数を使います。そうです、いつも型を確認するために使っていたあの関数(実際はクラス)です。
type(name, bases, dict, **kwds)
name | 生成するクラスの名前を指定する。 |
---|---|
based | 基底クラスをタプルで指定する。空の場合は object が指定される。 |
dict | クラスの属性を指定する。 |
型を動的に生成してみる
それでは、試しにMyClass
という簡単なクラスを動的に生成してみます。
# 動的に型を生成
MyClass = type('MyClass', (), {})
print(MyClass, type(MyClass))
# インスタンス化
mc = MyClass()
print(mc, type(mc))
実行結果
<class '__main__.MyClass'> <class 'type'>
<__main__.MyClass object at 0x104236fd0> <class '__main__.MyClass'>
動的に型を生成してインスタンス化することができました。
基底クラスの指定
第二引数にクラスを指定することで生成するクラスの親(基底クラス)を設定できる。親クラスはタプルで指定するが、空のタプルを指定するとobject
が設定される。
以下のコードでは、list
を継承させたクラスを動的に生成しています。
# listを継承したクラスを動的に生成
MyList = type('MyList', (list,), {})
print(MyList, type(MyList))
# インスタンス化
ml = MyList([1, 2, 3])
# listの機能を使う
ml.append(10)
ml.remove(2)
print(ml)
実行結果
<class '__main__.MyList'> <class 'type'>
[1, 3, 10]
親クラスはタプルとして指定する必要があるため(list,)
となっていることに注意。(list)
だとタプルではなくなってしまう。
属性の指定
第三引数では、辞書で属性を指定することができる。属性にはクラス変数やメソッドなどを渡すことができる。ちなみに、__init__
などの特殊メソッドも指定可能である。
# 渡す用の __init__
def __init__(self, a):
self.a = a
MyClass = type('MyClass', (), {'clsarg': 1, '__init__': __init__})
print(f'クラス変数 clsarg: {MyClass.clsarg}')
mc = MyClass(1)
print(f'インスタンス変数 a: {mc.a}')
実行結果
<class '__main__.MyClass'> <class 'type'>
クラス変数 clsarg: 1
インスタンス変数 a: 1
型オブジェクトはtypeのインスタンス
この記事では、動的に型を生成する方法を学んできましたが、実は通常のクラスもtype()
から生成されています。
実際に定義したクラスの型を確認してみます。
class MyClass:
pass
print(type(MyClass))
実行結果
<class 'type'>
MyClass
の型はtype
でした。
使い道
メタクラスを使ってクラス生成プロセスをカスタマイズする際に動的に型を生成する必要があります。
type
を継承させたクラス内の__new__
メソッドでクラスの生成方法を定義し、それを他のクラスにmetaclass
として渡します。そうすることでクラスオブジェクトがインスタンス化される際のプロセスを指定できます。
例えば以下のように使います。
-
STEP1メタクラスの準備クラスオブジェクトのインスタンス化の方法を定義したメタクラスの定義。この時に生成したクラスに属性を持たせたりすることができる。
class MetaClass(type): def __new__(cls, *args, **kwargs): # 動的にクラスを生成する c = type.__new__(cls, *args, **kwargs) # どのタイミングで実行されるか確認するための出力 print('MetaClass.__new__') # 生成したクラスを返す return c
-
STEP2メタクラスの指定クラスの
metaclass
にメタクラスを指定する。class MyClass(metaclass=MetaClass): pass
実行結果
MetaClass.__new__
MetaClass.__new__
メソッドに記述したprint()
が実行されたのでMyClass
を定義した時点で指定したメタクラスを使ってクラスオブジェクトが生成されたのがわかる。
このように、クラスの生成自体をカスタマイズすることができます。
まとめ
この記事では、Pythonで動的に型を生成する方法を解説しました。
動的に型を生成することでメタプログラミングをすることができますが、扱いが難しいので注意して使いましょう!
それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ