Ordering class methods without instantiating

Related : check .getmembers ok?

Background . I am trying to create a tool that generates a Python file according to a specific specification. One option is to provide as input a Python module containing an abstract class declaration and create a base class that inherits that abstract class but also adds a default implementation to all abstract methods.

For example: let's say I have the following file called Abstract.py

, which contains the following:

class Abstract(object):
    __metaclass__ = ABCMeta
    @abstractmethod
    def first(self):
        pass
    @abstractmethod
    def second(self):
        pass

      

So, the result of my tool will be a file named BaseClass.py

which contains:

class BaseClass(Abstract):
    def first(self):
        pass
    def second(self):
        pass

      

I want the methods in BaseClass

in the same order as in Abstract

.

My question is, is there a way to sort the methods according to their appearance without relying on the built-in method comparison (based on memory address comparisons)? I also hoped to avoid any kind of file handling if possible.

Please note that I am unable to instantiate Abstract

, so the solution mentioned in the above question will not work for me.

+3


source to share


1 answer


During class creation in Python2 (i.e. when the interpreter just gets a pass through the class body when running the file, which happens sequentially) - the class itself is created as an object. At this point, all the variables and methods defined in the class body are passed to the call to "type" (which is the default metaclass) as a dictionary.

As you know, dictionaries in Python are out of order, so this is usually not possible in Python2. This is possible in Python 3 because metaclasses can implement a method __prepare__

that returns a mapping object to be used to construct the body of the class, so it __prepare__

can return OrderedDict instead of a regular dict .

However, in your case, all the relevant methods are decorated @abstractmethod

- we can take advantage of this to not only annotate the methods as abstract, but also to mark the order in which they appear.

You can either wrap a decorator abstractclass

or create another decorator and use both. I would approve of a new decorator that does both to keep the linecount.



In addition, you need to choose how you will follow the order of the methods and use it. Usually repeating class attributes will just go through a dictionary (or rather a proxy dictionary), which is unordered, so you need to preserve the data structure to keep the ordered methods and the way to write that given order. There are some options out there, but perhaps the most direct one is to annotate the order of the method in the methods themselves and retrieve them by calling the inline sorted

with the appropriate parameter key

. Other facilities would require the decorator class or custom metaclass to work.

So here's an example of what I wrote about:

from abc import abstractmethod, ABCMeta

class OrderedAbstractMethod(object):
    def __init__(self):
        self.counter = 0
    def __call__(self,func):
        func._method_order = self.counter
        self.counter += 1
        return abstractmethod(func)

ordered_abstract_method = OrderedAbstractMethod()



class Abstract(object):
    __metaclass__ = ABCMeta
    @ordered_abstract_method
    def first(self):
        pass
    @ordered_abstract_method
    def second(self):
        pass
    @ordered_abstract_method
    def third(self):
        pass
    @ordered_abstract_method
    def fourth(self):
        pass


print "Unordered methods: ",[method[0] for method in   Abstract.__dict__.items() if not method[0].startswith("_") ]
# here it printed out -    ['second', 'third', 'fourth', 'first']

print "Ordered methods: ", sorted([method for method in   Abstract.__dict__.items() if not method[0].startswith("_") ], key= lambda m: m[1]._method_order)

      

+2


source







All Articles