たとえば、次のような基本クラスがあります。
class BaseClass(object):
def __init__(self, classtype):
self._type = classtype
このクラスから、他のいくつかのクラス、たとえば.
class TestClass(BaseClass):
def __init__(self):
super(TestClass, self).__init__('Test')
class SpecialClass(BaseClass):
def __init__(self):
super(TestClass, self).__init__('Special')
次のように、新しいクラスを現在のスコープに入れる関数呼び出しによって、これらのクラスを動的に作成するニース、Pythonの方法はありますか?
foo(BaseClass, "My")
a = MyClass()
...
なぜこれが必要なのかというコメントと質問があるので、派生クラスはすべて、コンストラクターが以前に未定義の引数をとるという違いを除いて、まったく同じ内部構造を持っています。したがって、たとえば、MyClass
はキーワードa
を取り、クラスTestClass
のコンストラクターはb
とc
を取ります。
inst1 = MyClass(a=4)
inst2 = MyClass(a=5)
inst3 = TestClass(b=False, c = "test")
ただし、クラスのタイプを入力引数として使用しないでください。
inst1 = BaseClass(classtype = "My", a=4)
私はこれを機能させましたが、他の方法、つまり動的に作成されたクラスオブジェクトを好むでしょう。
このコードを使用すると、動的な名前とパラメーター名を使用して新しいクラスを作成できます。 __init__
のパラメーター検証では、タイプなどの他の検証が必要な場合、またはそれらが必須であることを確認する必要がある場合、そこにロジックを追加するだけで、不明なパラメーターは許可されません。
class BaseClass(object):
def __init__(self, classtype):
self._type = classtype
def ClassFactory(name, argnames, BaseClass=BaseClass):
def __init__(self, **kwargs):
for key, value in kwargs.items():
# here, the argnames variable is the one passed to the
# ClassFactory call
if key not in argnames:
raise TypeError("Argument %s not valid for %s"
% (key, self.__class__.__name__))
setattr(self, key, value)
BaseClass.__init__(self, name[:-len("Class")])
newclass = type(name, (BaseClass,),{"__init__": __init__})
return newclass
そして、これは例えば次のように機能します:
>>> SpecialClass = ClassFactory("SpecialClass", "a b c".split())
>>> s = SpecialClass(a=2)
>>> s.a
2
>>> s2 = SpecialClass(d=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __init__
TypeError: Argument d not valid for SpecialClass
名前のスコープに動的な名前を挿入するように求めているのがわかります。現在、 that はPythonの良い習慣とはみなされていません。 、コーディング時に既知、またはデータ-ランタイムで学習された名前は「変数」よりも「データ」です-
したがって、クラスを辞書に追加して、そこから使用することができます。
name = "SpecialClass"
classes = {}
classes[name] = ClassFactory(name, params)
instance = classes[name](...)
また、デザインでスコープ内に名前が絶対に必要な場合は、同じことを行いますが、任意の辞書の代わりに globals()
呼び出しによって返される辞書を使用します。
name = "SpecialClass"
globals()[name] = ClassFactory(name, params)
instance = SpecialClass(...)
(実際にクラスファクトリ関数が呼び出し元のグローバルスコープに名前を動的に挿入することは可能ですが、それはさらに悪い習慣であり、Python実装間で互換性がありません。それを行う方法 sys._getframe(1) で呼び出し側の実行フレームを取得し、f_globals
属性でフレームのグローバル辞書にクラス名を設定します。
update、tl; dr:この回答は一般的になりましたが、それでも質問本体に非常に限定的です。 Pythonの "基本クラスから派生クラスを動的に作成する" の方法に関する一般的な答えは、新しいクラス名を渡すtype
の単純な呼び出しです。 、新しいクラスのベースクラスと__dict__
ボディを持つタプル-次のように:
>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})
update
これを必要とする人は、 dill プロジェクトもチェックする必要があります-pickleが通常のオブジェクトに対して行うのと同じように、クラスをpickleしたりunpickleしたりできると主張し、私のテストのいくつかでそれを実行しました。
type()
は、クラス(および特定のサブクラス)を作成する関数です。
def set_x(self, value):
self.x = value
SubClass = type('SubClass', (BaseClass,), {'set_x': set_x})
# (More methods can be put in SubClass, including __init__().)
obj = SubClass()
obj.set_x(42)
print obj.x # Prints 42
print isinstance(obj, BaseClass) # True