Страницы

Поиск по вопросам

среда, 10 июля 2019 г.

Порядковый номер атрибута класса

Добрый вечер. Есть класс (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']

Комментариев нет:

Отправить комментарий