Почему я должен использовать метод __prepare__ для получения пространства имен класса?
Примечание Этот вопрос не касается типа данных Python 3 Enum
, это просто пример, который я использую.
С PEP 3115 Python 3 добавил __prepare__
1 до type
с целью обеспечения использования пользовательского пространства имен при создании классов. Например, новый тип данных Enum
использует __prepare__
для возврата экземпляра private _EnumDict
для использования в качестве нового пространства имен Enum
.
Однако я видел несколько примеров, когда SO 2 of EnumMeta
был подклассом, создавая новое пространство имен для класса в методе 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)
:
from этот ответ
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)
Ответы
Ответ 1
Да, есть риски.
По крайней мере, существуют две причины для получения нового пространства имен, вызывая __prepare__
вместо выполнения type(clsdict)()
:
-
При запуске на Python 2 clsdict
есть dict
, а исходный __prepare__
никогда не запускался для начала (__prepare__
только Python 3) - другими словами, если __prepare__
возвращает что-то помимо нормального dict, type(clsdict)()
не получит его.
-
Любые атрибуты, установленные __prepare__
на clsdict
, не будут установлены при использовании type(clsdict)()
; т.е. если __prepare__
имеет clsdict.spam = 'eggs'
, то type(clsdict)()
не будет иметь атрибут spam
. Обратите внимание, что эти атрибуты находятся в самом пространстве имен для использования метаклассом и не отображаются в пространстве имен.
Подводя итог: есть веские причины использовать __prepare__()
для получения соответствующего словаря классов, а для ярлыка type(clsdict)()
нет.