2011-10-06 2 views
10

実行時にPythonでクラスを動的に作成したいと思います。実行時にクラスを作成するときに `type()`よりも `exec`を使う利点は何ですか?

例えば、私は以下のコードで複製したい:

>>> 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のクラス(すなわちたい:実行中の代わりに、最初のパス上をコンパイル)。これを達成するための

一つの方法はそうのように、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です。ちょうどどのようにpythonのcollections.namedtuple()クラスis implementedthis line参照)。また、クラス(Raymond Hettinger)の作成者がexechereのこの使用を防御することも非常に重要です。この防御では、 "は、名前付きタプルの重要な機能であり、手書きのクラスと全く同じです"と述べています。type()の使用がexec ...

違いがありますか?なぜexectype()を使用するのですか?

回答は、両方の方法が同じで、単純にnamedtuple実装に多数のnamedtuple変数があり、すべてのメソッドのクロージャを動的に生成すると、コードが扱いにくくなるしかし、これ以上何かがあるかどうかを知りたい。

execの私の不快感について、信頼できない当事者が悪意あるコードをそれに注入する方法がなければ、それはうまくいくはずです...それは私が緊張していることを確実にしています。

+1

http://blog.ccpgames.com/kristjan/2011/05/28/namedtuple-and-exec/でもこの問題に関する良い議論があり、それについての別の良いブログ記事がありました私は今見ていない。あなたの状況で 'type'が問題である理由を何も提示していないので、' type'が動作することを知っているので、 'exec'をどうして気にするのか分かりません。 (好奇心以外は明らかに)。 – agf

+0

@agf - 素晴らしいリンク、ありがとう!両方のアプローチが動作するので、私はもともと 'type'に問題がありませんでした。私はその違いについて興味があり、 'namedtuple'で' exec'を使う理由を理解しようとしていました。しかし、私は頻繁に[decorator](http://pypi.python.org/pypi/decorator)パッケージの使用を必要とするデコレータの問題を抱えています。 – Russ

+0

動的なクラス作成の必要性の背後にある理由を教えてもらえますか、それとも単に好奇心ですか? – dhill

答えて

2

execよりもtype()を使用することに不利な点はありません。私はレイモンドの防衛は少し守備だと思う。最も読みやすく分かりやすいテクニックを選択する必要があります。両方の方法で混乱するコードが作成されます。

最初にクラスを作成するコードを避けることは、本当に難しいことです。これが最適です。

+0

@agfL申し訳ありませんが、私はあなたが何を参照しているか分からない。 –

+3

'decorator'ライブラリの' exec'の引数の1つは、装飾された関数/メソッドの署名を保存する方が簡単だったということでした。私はそれが 'named'の引数でもあり、' exec'では手でコード化された場合と同じようにクラスが全く同じであったのに対し、 'type'では異なっていたと思います。 – agf

+0

私は間違いなくクラスを作成しないようにしたいと思いますが、クラス作成前にスコープ内にあることを保証できないパラメータに基づいてクラス属性を作成する必要がある場合があります。ダイナミッククラスは現時点では最も簡単な方法のようです。 – Russ

4

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

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

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

    Foo.__name__ = name 
    return Foo 
+0

実際には 'Foo'について_dynamic_何かがあるとき - あなたは毎回同じように基本的に作成したくありません。 – agf

+0

もちろん、これは単なるスケルトンです。 – yak

+0

このように 'namedtuple'やシグニチャを保持するデコレータを実装する方法を示してください。それは「決して柔軟性が低い」とは言えません。 – agf

7

typeexecよりここにお勧めします。実際に

class文はtypeへの呼び出しのためだけ糖衣構文です:クラス本体は、その後何のカスタムメタクラスが指定されていない場合typeデフォルトメタクラス、に渡される独自の名前空間内で実行されます。

このアプローチは、実行時にコードを解析する必要がないため、エラーが少なくなります。さらに高速に処理することもできます。

+0

+1実用性。 -1に値しません。 – agf