2011-10-06 19 views
10

我想在python中運行時動態創建類。在運行時創建類時,使用`exec'比type()`有什麼優勢?

例如,我想複製代碼如下:

>>> 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,富類(即:執行第一上通期間,而不是編譯)。實現這一

一種方法是用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 implemented(見this line)。由這個班級的創造者(Raymond Hettinger)來保護這種使用也是非常重要的。在這個辯護中,陳述「這是命名元組的一個關鍵特徵,它們完全等價於手寫類」,人們可能會認爲type()的使用不如使用exec ...

是否有區別?爲什麼使用exec vs type()

我希望答案可能是這兩個方面是相同的,它很簡單,就是namedtuple實施有很多通過它穿插namedtuple變量,並用這樣動態生成關閉了所有的方法使代碼得到笨拙,但我想知道是否還有更多的東西。

關於我對exec的不適感,我確實認識到,如果沒有任何方法讓不信任的人向其注入惡意代碼,那應該沒問題......它只是確保這讓我感到緊張。

+1

關於這個問題在http://blog.ccpgames.com/kristjan/2011/05/28/namedtuple-and-exec/上有一些很好的討論,並且還有一篇關於它的好博客文章我現在沒有看到。你沒有提出任何理由,爲什麼'type'在你的情況下是有問題的,所以我不知道你爲什麼會用'exec'來打擾你,因爲你知道'type'工作。 (顯然除了好奇)。 – agf

+0

@agf - 很棒的鏈接,謝謝!我原本沒有'type'的問題,因爲這兩種方法都有效。我只是對差異感到好奇,並試圖理解在'namedtuple'中使用'exec'的原因。提出的類/函數簽名參數是非常好的,但是...我經常遇到需要使用[裝飾器](http://pypi.python.org/pypi/decorator)包的修飾器問題。 – Russ

+0

您能否給出動態類創建需求背後的原因還是僅僅是好奇心? – dhill

回答

2

使用type()over exec沒有缺點。我認爲雷蒙德的防守有點防守。你必須選擇你發現最具可讀性和可理解性的技巧。這兩種方式都會產生混亂的代碼

你應該儘量避免創建類的代碼,這將是最好的。

+0

@agfL對不起,我不確定你指的是什麼。 –

+3

「decorator」庫的'exec'參數之一是保存裝飾函數/方法的簽名更容易。我認爲這也是'namedtuple'的一個參數,用'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

我會推薦type高於exec這裏。

事實上,class聲明僅僅是一個電話語法糖type:類主體自己的命名空間,然後到元類,默認爲type如果沒有指定自定義的元類通過內執行。

由於不需要在運行時解析代碼,並且甚至可能會更快一些,所以此方法不會出錯。

+0

+1爲實用性。不值得-1。 – agf

相關問題