How to Read Class Attributes in the Same Order as Declared

Reading class attributes in the same order as declared in Python

Your exact problem has a solution in Python3 using a metaclass. It's described in the docs.

However, it uses the __prepare__ classmethod, which is not available in Python2.7. After some googling I did find this solution that ports __prepare__ to Python2.7, but it's incredibly hacky and dirty.

To me it sounds like you're having the XY problem, and your problem can be solved through a different approach.

How to read order of declared members in Python class with use reflection or parsing (metaclass replace is forbidden)?

You'll have to resort to parsing. You don't need to write a parser here; the ast module can do this for you.

Parse the source with ast.parse(), then walk the resulting tree:

class ClassOrder(ast.NodeVisitor):
identifiers = None
def visit_ClassDef(self, node):
self.identifiers = []
for child in node.body:
if isinstance(child, ast.Assign):
for target in child.targets:
self.visit(target)
elif isinstance(child, ast.FunctionDef):
self.identifiers.append(child.name)
def visit_Name(self, node):
if self.identifiers is not None:
self.identifiers.append(node.id)

tree = ast.parse(sourcecode)
order = ClassOrder()
order.visit(tree)
print order.identifiers

prints out the order of assignments and methods in all class definitions.

Demo:

>>> sourcecode = '''\
... class A(object):
... b = 1
... a = 1
... c = 1
... '''
>>> tree = ast.parse(sourcecode)
>>> order = ClassOrder()
>>> order.visit(tree)
>>> print order.identifiers
['b', 'a', 'c']
>>> tree = ast.parse(inspect.getsource(ast.NodeVisitor))
>>> order = ClassOrder()
>>> order.visit(tree)
>>> print order.identifiers
['visit', 'generic_visit']

Bundled up as a function, using inspect.getsource():

import inspect

def get_identifiers(obj):
source = inspect.getsource(obj)
tree = ast.parse(source)
order = ClassOrder()
order.visit(tree)
return order.identifiers

inspect.getsource() can handle any object for which the source is available. For classes, it'll extract just the source block defining that class, if available.

class attributes declaration, order of the attributes' properties (final, private, static, type)

The language specification only says that modifiers must go before the type, thus int comes last.
Modifiers include type parameters, annotations, access modifiers (private, protected, public), static, final, synchronized, strictfp, volatile, transient and they (from "what allows the compiler") can come in any order.

Some days ago I did a google search and static final is much more often than final static, so this helps ordering them :-)

I think in general this order of the modifiers is most common:

  1. Annotations
  2. type parameters
  3. access modifiers
  4. static
  5. final
  6. transient (only for fields)
  7. volatile (only for variables)
  8. synchronized (only for methods)

I never used strictfp or native, but I think I would put them around synchronized.

How to iterate over a the attributes of a class, in the order they were defined?

I don't think this is possible in Python 2.x. When the class members are provided to the __new__ method they are given as a dictionary, so the order has already been lost at that point. Therefore even metaclasses can't help you here (unless there are additional features that I missed).

In Python 3 you can use the new __prepare__ special method to create an ordered dict (this is even given as an example in PEP 3115).

How to get class properties in order of declaration when serialize

Properties are not guaranteed to have or maintain any specific order in JavaScript. What you will do in your C# code can't change this "limitation".

BTW, the same goes for .net.

Kotlin get property in the same order they are declared

Easier way would be to read properties from the constructor:

 ClassWithSortedProperties::class.
primaryConstructor?.
parameters?.
forEachIndexed { i, property ->
println("$i $property")
}

Is the order of declarations within a class important?

It's important for the visibility of class members

class Account{
public:
Account(string firstName, string lastName, int id);
void printAccount();

Foo makeFoo(); // invalid! Foo not declared yet
typedef Foo foo_type; // invalid! Foo not declared yet

private:
string strLastName;
string strFirstName;
class Foo { };
};

You can only refer to a not yet declared name in a parameter, default argument, function body or constructor initialization list in class (or such things in nested classes). In other cases, you can't and you have to arrange declarations such that they are visible.

Get an ordered dictionary class attributes inside __init__

You can't do that, because the __init__ attribute called after that the instance has been created (by __new__()) so if you even override the __new__() and use a __prepare__ method using a metaclass, you can just get an ordered sequence (dict or etc.) of other methods and attributes which are not defined within __init__ method.

Also based on this mail:

It's just not possible to have something different than a dict as a type's __dict__. It's a deliberate limitation and required optimization.

But this doesn't mean that you can't get a list of ordered attributes of your class. Since every attribute sets by __setattr__ method you can simply preserve your attributes in an ordered dict by overriding the __setattr__ method:

from collections import OrderedDict

class NewName:
ordered_attrs = OrderedDict()
def __setattr__(self, name, val):
object.__setattr__(self, name, val)
# Use setattr(self, name, val) if you don't want to preserve the attributes in instances `__dict__`
NewName.ordered_attrs[name] = val

def __init__(self):
# your __init__ body

mynewname = NewName()
print(list(NewName.ordered_attrs))

Output:

['Name', 'DecomposedAlias', 'Meaning', 'SIUnit', 'NormalDisplayUnit', 'OrientationConvention', 'ContactPerson', 'Note', 'SubType', 'RefersTo']

# Output of mynewname.__dict__
{'Note': '', 'Meaning': '', 'RefersTo': [], 'SIUnit': OrderedDict([('ScaleFactor', None), ('Offset', None), ('A', None), ('cd', None), ('K', None), ('kg', None), ('m', None), ('mol', None), ('rad', None), ('s', None)]), 'DecomposedAlias': OrderedDict([('Prefix', None), ('Measurement', None), ('Direction', None), ('Item', None), ('Location', None), ('Descriptor', None), ('Frame', None), ('RTorigin', None)]), 'SubType': None, 'Name': None, 'ContactPerson': '', 'NormalDisplayUnit': OrderedDict([('ScaleFactor', None), ('Offset', None), ('A', None), ('cd', None), ('K', None), ('kg', None), ('m', None), ('mol', None), ('rad', None), ('s', None)]), 'OrientationConvention': ''}

Also regarding the setting the attributes, based on documentation:

If __setattr__() wants to assign to an instance attribute, it should call the base class method with the same name, for example, object.__setattr__(self, name, value).



Related Topics



Leave a reply



Submit