2017-05-06 50 views
10

注意這個問題不是關於Python 3 Enum數據類型,它只是我正在使用的示例。爲什麼我應該使用__prepare__方法來獲得類的名稱空間?

PEP 3115隨着Python 3的添加__prepare__ 方法type用於允許創建類時使用的自定義名稱空間的目的。例如,新的Enum數據類型使用__prepare__返回專用_EnumDict的實例,以用作新的Enum類的名稱空間。

然而,我看到的幾個例子對SO的EnumMeta 被子類,創建用於在元類__new__方法的類新的命名空間,但是,而不是調用__prepare__方法,以獲取新的命名空間,則使用type(clsdict)()代替。這樣做有風險嗎?


__prepare__簽名:

def __new__(metacls, cls, bases, clsdict, **kwds): 

實施例使用type(clsdict)

@classmethod 
def __prepare__(metacls, cls, bases, **kwds): 

__new__

this answer

class CountryCodeMeta(enum.EnumMeta): 
    def __new__(metacls, cls, bases, classdict): 
     data = classdict['data'] 
     names = [(country['alpha-2'], int(country['country-code'])) for country in data] 

    --> temp = type(classdict)() 
     for name, value in names: 
      temp[name] = value 

     excluded = set(temp) | set(('data',)) 
     temp.update(item for item in classdict.items() if item[0] not in excluded) 

     return super(CountryCodeMeta, metacls).__new__(metacls, cls, bases, temp) 

回答

8

是的,有風險。

至少有兩方面的原因,通過調用__prepare__而不是做type(clsdict)()獲得新的命名空間中:

  • 上的Python 2運行時clsdictdict,和原來的__prepare__絕然開始與(__prepare__只是Python 3) - 換句話說,如果__prepare__正在返回除正常詞典之外的東西,則type(clsdict)()不會得到它。

  • 使用type(clsdict)()時,clsdict上的__prepare__設置的任何屬性都不會設置;即如果__prepare__確實clsdict.spam = 'eggs'那麼type(clsdict)()將不具有spam屬性。請注意,這些屬性位於名稱空間本身以供元類使用,並且在命名空間中不可見。

總結:有使用__prepare__()以獲得正確的類字典很好的理由,並沒有爲type(clsdict)()快捷。

相關問題