Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read class attributes in the same order as declared?

I am writing a metaclass that reads class attributes and store them in a list, but I want the list (cls.columns) to respect the declaration order (that is: mycol2, mycol3, zut, cool, menfin, a in my example):

import inspect import pprint  class Column(object):     pass  class ListingMeta(type):     def __new__(meta, classname, bases, classDict):         cls = type.__new__(meta, classname, bases, classDict)         cls.columns = inspect.getmembers(cls, lambda o: isinstance(o, Column))          cls.nb_columns = len(cls.columns)         return cls  class Listing(object):     __metaclass__ = ListingMeta     mycol2 = Column()     mycol3 = Column()     zut = Column()     cool = Column()     menfin = Column()     a = Column()  pprint.pprint(Listing.columns) 

Result:

[('a', <__main__.Column object at 0xb7449d2c>),  ('cool', <__main__.Column object at 0xb7449aac>),  ('menfin', <__main__.Column object at 0xb7449a8c>),  ('mycol2', <__main__.Column object at 0xb73a3b4c>),  ('mycol3', <__main__.Column object at 0xb744914c>),  ('zut', <__main__.Column object at 0xb74490cc>)] 

This does not respect the declaration order of Column() attributes for Listing class. If I use classDict directly, it does not help either.

How can I proceed?

like image 517
Eric Avatar asked Dec 16 '10 10:12

Eric


People also ask

How do you access attributes of a class?

Attributes of a class can also be accessed using the following built-in methods and functions : getattr() – This function is used to access the attribute of object. hasattr() – This function is used to check if an attribute exist or not. setattr() – This function is used to set an attribute.

Can class attributes be inherited?

Objects are defined by classes, classes can inherit attributes and behavior from pre-existing classes. The resulting classes are known as derived classes or subclasses. A subclass “inherits” all the attributes (methods, etc) of the parent class.

What is the difference between class attributes and instance attributes?

Class attributes are the variables defined directly in the class that are shared by all objects of the class. Instance attributes are attributes or properties attached to an instance of a class. Instance attributes are defined in the constructor. Defined directly inside a class.


2 Answers

In the current version of Python, the class ordering is preserved. See PEP520 for details.

In older versions of the language (3.5 and below, but not 2.x), you can provide a metaclass which uses an OrderedDict for the class namespace.

import collections   class OrderedClassMembers(type):     @classmethod     def __prepare__(self, name, bases):         return collections.OrderedDict()      def __new__(self, name, bases, classdict):         classdict['__ordered__'] = [key for key in classdict.keys()                 if key not in ('__module__', '__qualname__')]         return type.__new__(self, name, bases, classdict)  class Something(metaclass=OrderedClassMembers):     A_CONSTANT = 1      def first(self):         ...      def second(self):         ...  print(Something.__ordered__) # ['A_CONSTANT', 'first', 'second'] 

This approach doesn't help you with existing classes, however, where you'll need to use introspection.

like image 118
Thomas Perl Avatar answered Sep 23 '22 21:09

Thomas Perl


Here is the workaround I juste developped :

import inspect  class Column(object):     creation_counter = 0     def __init__(self):         self.creation_order = Column.creation_counter         Column.creation_counter+=1  class ListingMeta(type):     def __new__(meta, classname, bases, classDict):         cls = type.__new__(meta, classname, bases, classDict)         cls.columns = sorted(inspect.getmembers(cls,lambda o:isinstance(o,Column)),key=lambda i:i[1].creation_order)          cls.nb_columns = len(cls.columns)         return cls  class Listing(object):     __metaclass__ = ListingMeta     mycol2 = Column()     mycol3 = Column()     zut = Column()     cool = Column()     menfin = Column()     a = Column()   for colname,col in Listing.columns:     print colname,'=>',col.creation_order 
like image 42
Eric Avatar answered Sep 24 '22 21:09

Eric