Search code examples
pythonreferencestaticfunction-pointersclass-variables

Python: How to fix, if a static class variable gets a different function reference pointer?


I wonder why my class calls the referenced function (assigned to a static class variable) with with an argument. If I assign the function reference to a normal class variable it works like expected.

Here my example code:

# This function is not editable, because it's imported from an API
def getStuff(): 
    print "I do my stuff!!!"

class foo(object):
    GET_STUFF = getStuff

    def __init__(self):
        print "static var: ",self.GET_STUFF
        self.GET_STUFF()

print "outer func: ",getStuff
foo()

This comes up with the following error:

outer func:  <function getStuff at 0x0000000003219908>
static var:  <bound method foo.getStuff of <__main__.foo object at 0x00000000030AB358>>
Traceback (most recent call last):
  File "C:/example.py", line 13, in <module>
    foo()
  File "C:/example.py", line 10, in __init__
    self.GET_STUFF()
TypeError: getStuff() takes no arguments (1 given)

To fix this issue I point the function reference inside the constructor to the class variable:

class foo(object):
    def __init__(self):
        self.GET_STUFF = getStuff
        print "static var: ",self.GET_STUFF
        self.GET_STUFF()

The result is like expected and works fine:

outer func:  <function getStuff at 0x000000000331F908>
static var:  <function getStuff at 0x000000000331F908>
I do my stuff!!!

But:

I wanted to use a static class variable, because it makes it easy to read and simple to setup for different API's. So in the end I would come up with some wrapper classes like in the following:

from API01 import getStuff01
from API02 import getStuff02

# bar calculates stuff object from the API (it calls GET_STUFF)
# and stores the object into self.stuff
import bar 

class foo01(bar):
    GET_STUFF = getStuff01

    def DoSomething(self, volume):
        self.stuff.volume = volume

class foo02(bar):
    GET_STUFF = getStuff02

    def DoSomething(self, volume):
        self.stuff.volume = volume

# [...] and so on..

Is there a way to bring it to work in the way I want to setup my wrapper classes, or do I really have to define a constructor for each wrapper class?

Thanks


Solution

  • I thought already that my object is calling the referenced function with itself as argument. After a bit of research I finally found a solution. When I use a class variable to point to a function it will not referencing a direct pointer. It references the function as a bounced method of it's class. To get rid of the default call of calling a method with getattr, the call function of getattr for the class itself has to be overwritten (in this case the class bar, because foo (the wrapper classes) inherits the functionalities of bar:

    import inspect
    
    class bar(object):
        GET_STUFF = None
    
        def __getattribute__(self, name):
            attr = object.__getattribute__(self,name)
            if name == "GET_STUFF":
                # Check: is method and is bounced?
                if inspect.ismethod(attr) and attr.im_self is not None:
                    return attr.__func__
            return attr
    

    getattr of bar is now pointing to the original function reference, but only for the class variable GET_STUFF, because I want to leave the default functionality for the rest of my variables.

    So, when I now execute the following:

     class foo(bar):
        GET_STUFF = getStuff
    
        def __init__(self):
            print "inner func: ",self.GET_STUFF
            self.GET_STUFF()
    
    foo()
    

    I get the expected result and can write my wrappers without producing additional code for each module with those wrapper classes:

    outer func:  <function getStuff at 0x00000000034259E8>
    inner func:  <function getStuff at 0x00000000034259E8>
    I do my stuff!!!