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.
source to share
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)
source to share