Как упоминалось выше, если вы хотите, чтобы все было просто, просто используйте, например, атрибут _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)]
Не стесняйтесь изменить это на упорядоченный dict или просто вернуть имена или все, что вам нужно. Кроме того, вы можете определить пустой класс с помощью __metaclass__
и наследовать его.
Не используйте это!
Как видите, этот подход немного усложнен и, вероятно, не подходит для большинства задач или разработчиков Python. Если вы новичок в python, вы, вероятно, потратите больше времени и усилий на разработку своего метакласса, чем если бы вы просто определили порядок вручную. Определение собственного порядка вручную почти всегда будет лучшим подходом. Django делает это автоматически, потому что сложный код скрыт от конечного разработчика, а Django используется гораздо чаще, чем сам пишется/поддерживается. Так что метаклассы могут быть вам полезны только в том случае, если вы разрабатываете фреймворк для других разработчиков.
person
Will Hardy
schedule
20.07.2010