Добрый вечер.
Есть класс (mongoengine):
class BaseMetaDocument(Document):
unit = StringField()
name = StringField()
active = BooleanField()
Как получить, что порядковый номер unit=1, name=2, active=3?
Сейчас я просто добавил свойство order=1,2,3 и т.д. для каждого поля, может есть какой то более простой способ?
Ответ
Это невозможно (можно создать вспомогательный индекс - см. обновление ниже). Все аттрибуты хранятся в поле __dict__. Это словарь, а словарь не гарантирует сохранения порядка элементов. Например:
class CL:
bar = "a"
boo = "b"
spam = "c"
print(CL.__dict__)
Результат: {'__module__': '__main__', 'spam': 'c', 'bar': 'a', '__doc__': None, 'boo': 'b'}
Как видно, порядок совсем другой. В качестве запасного выхода можно добавить аттрибут index = ["bar", "boo", "spam"] и получать значения примерно так: getattr(CL(), CL.index[0])
Обновление с метаклассами:
Согласно PEP 3115 - возможно сохранить порядок полей на этапе создания класса. Тело класса обрабатывается как обычный код, но словарь, в котором хранятся локальные переменные, заменяется на нашу структуру. Например, OrderedDict, чтобы запомнить порядок. Такой подход не избавляет от специального аттрибута с индексом, но так нет необходимости заполнять его вручную и следить за тем, чтобы ничего не забыть туда добавить. Делается это таким образом:
from collections import OrderedDict
class Meta(type) :
@classmethod
def __prepare__(metacls, name, bases):
print("META for {name} prepare".format(name=name))
return OrderedDict()
def __new__(self, name, bases, __dict__):
# Мы не продолжаем использовать OrderedDict(), класс все равно создается со словарем
__dict__['index'] = [key for key in __dict__ if key not in ('__module__', '__qualname__')]
return type.__new__(self, name, bases, __dict__)
class MyClass(metaclass=Meta):
bar = "a"
foo = "yo!"
def method(self):
pass
baz = 123
spam = [1, 2, 3, 4, 5]
print(MyClass.index)
Вывод: ['bar', 'foo', 'method', 'baz', 'spam']
Комментариев нет:
Отправить комментарий