本文介绍了为什么要使用__prepare__方法获取类的名称空间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意 该问题与Python 3 Enum数据类型无关,这只是我正在使用的示例.

Note This question is not about the Python 3 Enum data type, it's just the example I'm using.

PEP 3115 中,Python 3添加了 __prepare__ 方法用于允许在创建类时使用自定义名称空间.例如,新的Enum数据类型使用__prepare__返回专用_EnumDict的实例,以用作新的Enum类的名称空间.

With PEP 3115 Python 3 added the __prepare__ method to type for the purpose of allowing a custom namespace to be used when creating classes. For example, the new Enum data type uses __prepare__ to return an instance of the private _EnumDict for use as the new Enum class' namespace.

但是,我已经看到关于EnumMeta的SO 的几个示例被子类化,在元类__new__方法中为该类创建了一个新的命名空间,但是没有调用__prepare__获取新名称空间的方法,而是使用type(clsdict)().这样做会有任何风险吗?

However, I have seen several examples on SO of EnumMeta being subclassed, creating a new namespace for the class in the metaclass __new__ method, but instead of calling the __prepare__ method to acquire that new namespace, type(clsdict)() is used instead. Are there any risks to doing it this way?

__prepare__的签名:

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

__new__:

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


使用type(clsdict)的示例:


Example using type(clsdict):

来自此答案

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)

推荐答案

是的,存在风险.

至少有两个原因可以通过调用__prepare__而不是执行type(clsdict)()来获取新的名称空间:

At least two reasons exist for getting the new namespace by calling __prepare__ instead of doing type(clsdict)():

  • 在Python 2上运行时clsdictdict,原始的__prepare__从不运行(以__prepare__仅适用于Python 3)开头-换句话说,如果__prepare__除了正常的字典以外还返回其他内容,type(clsdict)()不会得到它.

  • When running on Python 2 clsdict is a dict, and the original __prepare__ never ran to begin with (__prepare__ is Python 3 only) -- in other words, if __prepare__ is returning something besides a normal dict, type(clsdict)() is not going to get it.

使用type(clsdict)()时,不会设置clsdictclsdict上设置的任何属性;也就是说,如果__prepare__执行clsdict.spam = 'eggs',则type(clsdict)()将没有spam属性.请注意,这些属性位于供元类使用的名称空间本身上,并且在名称空间中不可见.

Any attributes set by __prepare__ on the clsdict would not be set when using type(clsdict)(); i.e. if __prepare__ does clsdict.spam = 'eggs' then type(clsdict)() will not have a spam attribute. Note that these attributes are on the namespace itself for use by the metaclass and are not visible in the namespace.

总结:有充分的理由使用__prepare__()获取正确的类字典,而没有任何理由使用type(clsdict)()快捷方式.

To summarize: there are good reasons to use __prepare__() to obtain the proper class dictionary, and none for the type(clsdict)() shortcut.

这篇关于为什么要使用__prepare__方法获取类的名称空间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 04:47