なにかの処理をスクリプトでやらせるとき、私はたいていconfigファイルを外出しにし設定値をそこに集約させ、実行するときにそのconfigを読み込ませて処理実行することにしています。
設定値の中でも、ある処理を特定のクラスで実行させたいときがありました。
こういった時どうしたらいいでしょうか?
数値などのパラメータを書いておいて、例えば1だったらClassA、2だったらClassBなど、コードの中でif分で分けてクラス生成しますか?
新しくClassCのパターンが必要になったら、コードのif分を追加しないといけませんね。
pythonであればglobals()を使えば文字列からクラスオブジェクトを生成することができるので、こういった時に便利です。
(更新)
コメントにありましたようにeval関数でも文字列からクラスオブジェクトを生成することができます。
globals()
globals()関数を使うと実現できます。globals()は現在読み込んでいるモジュールの辞書を返してきます。これを使って文字列からクラスを生成することができます。
サンプルコード
サンプルコードです。
# 親クラス
class Parent(object):
def __init__(self):
pass
def call(self):
print("I am parent.")
# 子クラス その1
class ChildAsBrother(Parent):
def __init__(self):
super().__init__()
def call(self):
print("I am child as brother.")
# 子クラス その2
class ChildAsSister(Parent):
def __init__(self):
super().__init__()
def call(self):
print("I am child as sister.")
# 通常のオブジェクト生成と呼び出し
obj = Parent()
obj.call()
obj = ChildAsBrother()
obj.call()
# globals()を使ったオブジェクト生成
obj = globals()["ChildAsSister"]() # <--- 文字列からオブジェクト生成することができる
obj.call()
# 追加
# evalを使った方法
obj = eval("ChildAsSister")()
obj.call()
obj = eval("ChildAsSister()")
obj.call()
実行結果はこうなります。
I am parent.
I am child as brother.
I am child as sister.
I am child as sister.
I am child as sister.
このように使えばconfigファイルに使いたいクラス名を指定しておいて、それをコードの中で直接使うことができます。便利ですねー
そもそもglobals()って...
そもそもglobals()は具体的に何を返してくるんでしょう。
ちょっと確認してみました。ここは参考までにご紹介します。
print(globals())
# 実際は1行で表示されますが見にくいので改行してます。
{'__name__': '__main__',
'__doc__': None,
'__package__': None,
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0xffdc5c90>,
'__spec__': None,
'__annotations__': {},
'__builtins__': <module 'builtins' (built-in)>,
'__file__': 'parent_child.py',
'__cached__': None,
'Parent': <class '__main__.Parent'>,
'ChildAsBrother': <class '__main__.ChildAsBrother'>,
'ChildAsSister': <class '__main__.ChildAsSister'>,
'obj': <__main__.ChildAsSister object at 0xffd18b90>}
詳しいことはわかりませんが、メタデータや実行環境でのクラスやオブジェクトなどが管理されているようですね。
その中のクラスを実行しているみたいです。