Как уже упоминалось выше, если вы хотите сохранить простоту, просто используйте, например, атрибут _ordering
, который вручную отслеживает порядок.В противном случае, здесь используется метаклассовый подход (аналогичный тому, который использует Django), который автоматически создает атрибут порядка.
Запись исходного порядка
Классы не отслеживаютсяупорядочения атрибутов.Однако вы можете отслеживать, в каком порядке были созданы экземпляры полей.Для этого вам нужно будет использовать свой собственный класс для полей (не int).Класс отслеживает, сколько экземпляров уже сделано, и каждый экземпляр отмечает свою позицию.Вот как это делается для вашего примера (хранение целых чисел):
class MyOrderedField(int):
creation_counter = 0
def __init__(self, val):
# Set the instance's counter, to keep track of ordering
self.creation_counter = MyOrderedField.creation_counter
# Increment the class's counter for future instances
MyOrderedField.creation_counter += 1
Автоматическое создание атрибута ordered_items
Теперь, когда ваши поля имеют номеркоторый может быть использован для их упорядочения, ваш родительский класс должен каким-то образом это использовать.Вы можете сделать это различными способами, если я правильно помню, Django использует для этого метаклассы, что немного странно для простого класса.
class BaseWithOrderedFields(type):
""" Metaclass, which provides an attribute "ordered_fields", being an ordered
list of class attributes that have a "creation_counter" attribute. """
def __new__(cls, name, bases, attrs):
new_class = super(BaseWithOrderedFields, cls).__new__(cls, name, bases, attrs)
# Add an attribute to access ordered, orderable fields
new_class._ordered_items = [(name, attrs.pop(name)) for name, obj in attrs.items()
if hasattr(obj, "creation_counter")]
new_class._ordered_items.sort(key=lambda item: item[1].creation_counter)
return new_class
Использование этого метакласса
Итак, как вы используете это?Во-первых, вам нужно использовать наш новый класс MyOrderedField
при определении ваших атрибутов.Этот новый класс будет отслеживать порядок, в котором были созданы поля:
class Ordered(object):
__metaclass__ = BaseWithOrderedFields
x = MyOrderedField(0)
z = MyOrderedField(0)
b = MyOrderedField(0)
a = MyOrderedField(0)
Затем вы можете получить доступ к упорядоченным полям в нашем автоматически созданном атрибуте ordered_fields
:
>>> ordered = Ordered()
>>> ordered.ordered_fields
[('x', 0), ('z', 0), ('b', 0), ('a', 0)]
Не стесняйтесь сменить это на заказанный диктат или просто вернуть имена или все, что вам нужно.Кроме того, вы можете определить пустой класс с помощью __metaclass__
и наследовать оттуда.
Не используйте это!
Как видите, этот подходнемного сложнее и, вероятно, не подходит для большинства задач или разработчиков Python.Если вы новичок в Python, вы, вероятно, потратите больше времени и усилий на разработку своего метакласса, чем если бы вы просто определили порядок вручную.Определение собственного заказа вручную почти всегда будет лучшим подходом.Django делает это автоматически, потому что сложный код скрыт от конечного разработчика, и Django используется гораздо чаще, чем сам написан / поддерживается.Поэтому, только если вы разрабатываете фреймворк для других разработчиков, метаклассы могут быть вам полезны.