Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get method of a class in the order that it was in the code

This code:

import inspect

class Obj():

    def c(self):
        return 1

    def b(self):
        return 2

    def a(self):
        return 3

o = Obj()

for name, value in inspect.getmembers(o, inspect.ismethod):
    print str(value())+" "+name

print:

3 a
2 b
1 c

Because of inspect.getmembers return all the members of an object in a list of (name, value) pairs sorted by name, as you can read in https://docs.python.org/2/library/inspect.html#inspect.getmembers

But I want to get that list in the same order that the members was written in the code, in other words, the output would be:

1 c
2 b
3 a

Is any way to do that?

Thanks

like image 229
santos82h Avatar asked Apr 06 '17 17:04

santos82h


People also ask

How do you order a class method?

Member variables at the top of the class, then constructors, then all other methods. And you order the methods to be close together with how they are used within the class (rather than arbitrarily putting all public then private then protected).

How do you sort methods in python?

As a rule of thumb, put methods above all methods called from their body. Class methods and static methods: Usually, this is implied by the reading order explained above. Normal methods can call all methods times and thus come first. Class methods can only call class methods and static methods and come next.

Does order of methods in a class matter?

No it does not matter at all where in the class the method declaration is placed. When you actually call a method Java will go through the entire class looking for it either way, so the placement is irrelevant.

Do the order of methods matter in Java?

Abstract—As the order of methods in a Java class has no effect on its semantics, an engineer can choose any order she prefers.


2 Answers

No. Class members are not ordered. They are gathered into a dictionary, immediately losing order. You can resort to tricks like parsing the source, but it will break easily. For starters, the source could not be available.

[edit: it seems python3 allows more flexibility in class creation, making it possible to customize the way class members are gathered, if you are on python3 only, that's probably a better approach]

If changing the code is not a problem, you can use a decorator though:

import inspect

def track_order(fn):
    fn.order = track_order.idx
    track_order.idx += 1
    return fn
track_order.idx = 0

class Obj(object):
    @track_order
    def c(self):
        return 1

    @track_order
    def b(self):
        return 2

    @track_order
    def a(self):
        return 3

o = Obj()

methods = sorted((item
                  for item in inspect.getmembers(o, inspect.ismethod)),
                 key=lambda item: item[1].order)

for name, value in methods:
    print str(value())+" "+name

The decorator adds an idx attribute to all methods that pass through it. This makes use of the fact that python has first-class functions.

$ python test.py
1 c
2 b
3 a

Note: this is the method used by Django to keep track of form and model fields order. Only, they don't need a decorator because fields' classes have the instanciation order attribute built-in (it is named creation_counter).

like image 170
spectras Avatar answered Sep 19 '22 08:09

spectras


When creating an object, all of its attributes are contained in another specialized attribute in the object called __dict__, which as the name suggests is just a normal Python non-ordered dictionary, hence they are not guaranteed to be stored in the same fashion they were added in. When retrieving the values in __dict__ using getmembers(), Python automatically reorganizes the dictionary when printing it in order to make some logical sense.

To combat this, something must be done to turn the regular Python dictionary __dict__ into some sort of ordered one.

This can be done a number of ways, for simplicity's sake, I will assume you are using Python 3.

Using the collections package, you can obtain an OrderedDict, which is exactly the technology we require for such an issue. Prepare this ordered dictionary for use in a metaclass for the class which needs ordered members to be stored, copy over the members, and finally access this new OrderedDict when wanting to print out said members.

This can be seen in action in this Stack Overflow answer.

like image 22
Ziyad Edher Avatar answered Sep 18 '22 08:09

Ziyad Edher