Adventures in Meta programming in Python
function_class = MyClass.foo.im_class
This is useful if you pass in an instance method somewhere and you want to be able to access its attached class. Decorators on instance methods normally use this, but I needed it to get a nicer syntax on my asserts, I wanted this:
So now when I want to track what class is passed in I just have to start with the following:
classdef = method.im_class #I get the method and the class in one parameter!
module = __import__(“foomodule”)
this creates a module import by string. This becomes super powerful say if you wanted to replace functionality on a module, but didn’t know its name before hand. In my case I wanted to be able to patch in a replacement method for mocking and then put it back when I was done, and I didn’t want to have to keep passing in the module name on resets. The only downside to it so far is it behaves a little quirky with packages and you have walk your module hierarchy to get it to do what you want
example of patching originals back into the module:
modulename = mod[]
methodname = mod[1]
module = __import__(modulename) #this is the magic. if module name has no package aka : “barmod” this will work. if its “foopackage.barmod” it’ll import the “foopackage”
for i in modulename.split(“.”)[1:]: #works down the chain
module = getattr(module, i) #resets the module variable with the lower hierarchy module
setattr(module, methodname, original) #actually pass the original function object back onto the module.
MyClass.__getattribute__ = interception
__getattribute__ is called when any attribute is accessed on a class including __getattribute__ itself which is a bit silly. This was the primary engine of my mocking framework as it allowed me to record all calls to the methods on a mocked class. Just remember when you use this to have it not call itself or you’ll be in endless recursion!
example:
def stuff(self):
pass
def interceptor(self, name):
if name == “__getattribute__”: #guard condition against calling itself
return object.__getattribute__(self, name)
#whatever interception logic you need here
MyClass.__getattribute__ = interceptor
m = MyClass()
m.stuff() #interception logic will be called here
I’m just starting to dip into the Python object model now and I’ll try and share what I find over the next few weeks.