简体   繁体   中英

attribute assignment order in class definition

I want to define a class in this way:

class List(Base):
    hp = Column(int,...)
    name = Column(str,...)

This class represents a list, I can define/modify/code the Base and the Column class. There's a way to know the order in which I defined the attributes hp/names? For example I want to define a method that can do this:

l = List()
l.show()
[(hp,16),(name,roger)] # in this order

Internally, attribute definitions are stored in a dictionary, which does not retain the order of the elements. You could probably change the attribute handling in the Base class, or you store the creation order, like this:

class Column:
    creation_counter = 0

    def __init__(self):
            self.creation_counter = Column.creation_counter
            Column.creation_counter += 1

class Base:
    def show(self):
        fields = [(name, (obj, obj.value)) for name, obj in self.__class__.__dict__.items() if isinstance(obj, Column)] 
        fields.sort(lambda (name1, (obj1, value1)), (name2, (obj2, value2)): cmp(obj1.creation_counter, obj2.creation_counter))
        return fields

Django stores the order of form fields in a similar way, albeit way more sophisticated. If you are interested, look at the source of Django forms and fields

I think you want something like this:

import inspect

class List(Base):
    hp = Column(int,...)
    name = Column(str,...)

    def show(self):
        public_bits = [(x, getattr(self, x)) for x in dir(self) if not x.startswith('__')]
        return [(x, y) for (x, y) in public_bits if not inspect.ismethod(y)]

Sadly, dir returns attributes in alphabetical order, so this may not exactly solve your problem.

Class and instance attributes are inherently unordered since they are stored in a dictionary.

There are a few options though:

1) classes defined with __slots__ do not use a dictionary, and the space for attributes are pre-allocated. I presume that the attributes are therefore ordered, so it should be possible in principle to get the data out. There are issues with using slots though, and it is not recommended.

2) add a list/tuple attribute to the class with the attribute order.

3) use a collection.namedtuple object to store the attributes. A namedtuple is a tuple where you can give names to the elements, and so is similar to a C struct. This will only work from Python 2.6 onwards. Since tuples are immutable you will not be able modify the attributes once created - this may or may not be a problem depending on the class.

Edit:

On reflection __slots__ will not work, since I think they only apply to instances and not class attributes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM