Как перебирать атрибуты класса в том порядке, в котором они были определены? [дубликат]

этот вопрос уже есть ответ здесь:

Python поставляется с удобным dir() функция, которая будет перечислять содержимое класса для вас. Например, для этого класса:

class C:
   i = 1
   a = 'b'

dir(C) будет возвращение

['__doc__', '__module__', 'a', 'i']

это здорово, но обратите внимание, как порядок 'a' и 'i' теперь отличается от того порядка, в котором они были определены.

как я могу перебирать атрибуты C (потенциально игнорируя встроенные атрибуты doc & module) в том порядке, в котором они были определены? Для класса C выше, будет 'i' затем 'a'.

добавление: - Я работаю над некоторым кодом сериализации / регистрации, в котором я хочу сериализовать атрибуты в порядке они были определены так, чтобы выходные данные были похожи на код, который создал класс.

4 ответов


Я не думаю, что это возможно в Python 2.X. Когда члены класса предоставляются __new__ метод они даны как словарь, поэтому порядок уже был потерян в этот момент. Поэтому даже метаклассы не могут помочь вам здесь (если нет дополнительных функций, которые я пропустил).

в Python 3 Вы можете использовать новый __prepare__ специальный метод для создания упорядоченного dict (это даже приведено в качестве примера в PEP 3115).


Я новичок в python, поэтому мое решение может быть неэффективным

class Q:
def __init__(self):
    self.a = 5
    self.b = 10

if __name__ == "__main__":
    w = Q() 
    keys = w.__dict__.keys()
    for k in keys:
        print "Q.%s = %d"%(k,w.__dict__[k])

вывод:

Q.a = 5
Q.b = 10

поставить этот метод в свой класс

def __setattr__(self, attr, value):
    if attr not in dir(self):
        if attr == "__ordered_fields__":
            super.__setattr__(self, attr, value)
        else:
            if not hasattr(self, "__ordered_fields__"):
                setattr(self, "__ordered_fields__", [])
            self.__ordered_fields__.append(attr)
            super.__setattr__(self, attr, value)

и чтобы привести поля в порядок, просто сделайте что-то вроде:

print(self.__ordered_fields__)

эта информация недоступна, так как атрибуты хранятся в dict, который по своей сути неупорядочен. Python не хранит эту информацию о заказе нигде.

Если вы хотите, чтобы ваш формат сериализации хранил вещи в определенном порядке, вы бы указать это порядок явно. Вы не будете использовать dir, который содержит вещи, о которых вы не знаете или не заботитесь, вы бы явно предоставили список (или что-то еще), описывающий, что сериализовать.