问题描述
注意 该问题与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上运行时
clsdict
是dict
,原始的__prepare__
从不运行(以__prepare__
仅适用于Python 3)开头-换句话说,如果__prepare__
除了正常的字典以外还返回其他内容,type(clsdict)()
不会得到它.
When running on Python 2
clsdict
is adict
, 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)()
时,不会设置clsdict
在clsdict
上设置的任何属性;也就是说,如果__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__方法获取类的名称空间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!