为什么要使用 __prepare__ 方法来获取 class' 命名空间?
Why should I use the __prepare__ method to get a class' namespace?
注意 这个问题不是关于 Python 3 Enum
数据类型的,它只是我正在使用的例子。
使用 PEP 3115 Python 3 added the __prepare__
1 方法到 type
目的是允许在创建 classes 时使用自定义命名空间。例如,新的Enum
数据类型使用__prepare__
到return私有_EnumDict
的一个实例作为新的Enum
class'命名空间。
但是,我在 EnumMeta
的 SO2 上看到几个例子被子class编辑,为 [=60= 创建一个新的命名空间] 在 metaclass __new__
方法中,但不是调用 __prepare__
方法来获取新的命名空间,而是使用 type(clsdict)()
。这样做有什么风险吗?
1 __prepare__
的签名:
@classmethod
def __prepare__(metacls, cls, bases, **kwds):
和 __new__
:
def __new__(metacls, cls, bases, clsdict, **kwds):
2 使用 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)()
获取新命名空间至少有两个原因:
当运行 on Python 2 clsdict
是一个dict
,而原来的__prepare__
永远不会运行开始于(__prepare__
仅是 Python 3)——换句话说,如果 __prepare__
返回的不是普通字典,type(clsdict)()
就不会得到它。
__prepare__
在 clsdict
上设置的任何属性在使用 type(clsdict)()
时都不会设置;即如果 __prepare__
做 clsdict.spam = 'eggs'
那么 type(clsdict)()
将没有 spam
属性。请注意,这些属性在命名空间本身上供元class使用,并且在命名空间中不可见。
总而言之:使用 __prepare__()
获取正确的 class 字典,使用 none 作为 type(clsdict)()
快捷方式是有充分理由的。
注意 这个问题不是关于 Python 3 Enum
数据类型的,它只是我正在使用的例子。
使用 PEP 3115 Python 3 added the __prepare__
1 方法到 type
目的是允许在创建 classes 时使用自定义命名空间。例如,新的Enum
数据类型使用__prepare__
到return私有_EnumDict
的一个实例作为新的Enum
class'命名空间。
但是,我在 EnumMeta
的 SO2 上看到几个例子被子class编辑,为 [=60= 创建一个新的命名空间] 在 metaclass __new__
方法中,但不是调用 __prepare__
方法来获取新的命名空间,而是使用 type(clsdict)()
。这样做有什么风险吗?
1 __prepare__
的签名:
@classmethod
def __prepare__(metacls, cls, bases, **kwds):
和 __new__
:
def __new__(metacls, cls, bases, clsdict, **kwds):
2 使用 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)()
获取新命名空间至少有两个原因:
当运行 on Python 2
clsdict
是一个dict
,而原来的__prepare__
永远不会运行开始于(__prepare__
仅是 Python 3)——换句话说,如果__prepare__
返回的不是普通字典,type(clsdict)()
就不会得到它。__prepare__
在clsdict
上设置的任何属性在使用type(clsdict)()
时都不会设置;即如果__prepare__
做clsdict.spam = 'eggs'
那么type(clsdict)()
将没有spam
属性。请注意,这些属性在命名空间本身上供元class使用,并且在命名空间中不可见。
总而言之:使用 __prepare__()
获取正确的 class 字典,使用 none 作为 type(clsdict)()
快捷方式是有充分理由的。