10

Pythonで実行時にクラスを動的に作成したい。

たとえば、次のコードを複製します。

>>> class RefObj(object):
...     def __init__(self, ParentClassName):
...         print "Created RefObj with ties to %s" % ParentClassName
... class Foo1(object):
...     ref_obj = RefObj("Foo1")
... class Foo2(object):
...     ref_obj = RefObj("Foo2")
... 
Created RefObj with ties to Foo1
Created RefObj with ties to Foo2
>>>

...しかし、Foo1、Foo2、Foo クラスを動的に作成したい (つまり、最初のパスのコンパイルではなく実行中に)。

これを実現する 1 つの方法は、次type()のように を使用することです。

>>> class RefObj(object):
...     def __init__(self, ParentClassName):
...         print "Created RefObj with ties to %s" % ParentClassName
... def make_foo_class(index):
...     name = "Foo%s" % index
...     return type(name, (object, ), dict(ref_obj = RefObj(name)))
... 
>>> Foo1 = make_foo_class(1)
Created RefObj with ties to Foo1
>>> Foo2 = make_foo_class(2)
Created RefObj with ties to Foo2
>>> type(Foo1()), type(Foo2())
(<class 'Foo1'>, <class 'Foo2'>)

exec次のように、でそれを達成することもできます。

>>> class RefObj(object):
...     def __init__(self, ParentClassName):
...         print "Created RefObj with ties to %s" % ParentClassName
... def make_foo_object(index):
...     class_template = """class Foo%(index)d(object):
...         ref_obj = RefObj("Foo%(index)d")
...         """ % dict(index = index)
...     global RefObj
...     namespace = dict(RefObj = RefObj)
...     exec class_template in namespace
...     return namespace["Foo%d" % index]
... 
>>> Foo1 = make_foo_object(1)
Created RefObj with ties to Foo1
>>> Foo2 = make_foo_object(2)
Created RefObj with ties to Foo2
>>> type(Foo1()), type(Foo2())
(<class 'Foo1'>, <class 'Foo2'>)

の使用はexec私にはうまくいきません(この質問を読んだ多くの人にはそうではないと思います)が、execまさにpythoncollections.namedtuple()クラスがどのように実装されているかです(この行を参照)。また、クラスの作成者 (Raymond Hettinger) による、exec hereの使用に対する弁護も非常に関連性があります。この弁護では、「名前付きタプルの重要な機能は、手書きのクラスとまったく同等である」と述べtype()られていexecます。

違いはありますか?execvsをtype()使用する理由

答えは、両方の方法が同じであり、namedtuple実装に多くの名前付きタプル変数が散りばめられているだけであり、すべてのメソッドのクロージャーを動的に生成してこれを行うと、コードが扱いにくくなる可能性があると思いますが、知りたいですこれにさらに何かがある場合。

に対する私の不快感についてはexec、信頼できない関係者が悪意のあるコードを挿入する方法がまったくない場合は、それで問題ないことを認識しています...それが私を緊張させるだけです.

4

3 に答える 3

7

私はここをお勧めtypeexecます。

実際、classステートメントは への呼び出しの単なる構文糖衣ですtype。クラス本体は独自の名前空間内で実行され、メタクラスに渡されます。これは、typeカスタム メタクラスが指定されていない場合のデフォルトです。

このアプローチは、実行時にコードを解析する必要がないため、エラーが発生しにくく、さらに高速になる可能性があります。

于 2011-10-06T16:18:59.173 に答える
4

関数でクラスを作成しないのはなぜですか?

def foo_factory(index):
    name = 'Foo%d' % index

    class Foo(object):
        ref_obj = RefObj(name)

    Foo.__name__ = name
    return Foo
于 2011-10-06T16:06:23.693 に答える
2

exec よりも type() を使用することにデメリットはありません。レイモンドの防御は少し守備的だと思います。最も読みやすく理解しやすい手法を選択する必要があります。どちらの方法でも、紛らわしいコードが作成されます。

最初にクラスを作成するコードを避けるように一生懸命努力する必要があります。それが最善です。

于 2011-10-06T16:10:39.743 に答える