2017-05-06 64 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)()快捷。

相关问题