Python decorator as a staticmethod Python decorator as a staticmethod python python

Python decorator as a staticmethod


This is not how staticmethod is supposed to be used. staticmethod objects are descriptors that return the wrapped object, so they only work when accessed as classname.staticmethodname. Example

class A(object):    @staticmethod    def f():        passprint A.fprint A.__dict__["f"]

prints

<function f at 0x8af45dc><staticmethod object at 0x8aa6a94>

Inside the scope of A, you would always get the latter object, which is not callable.

I'd strongly recommend to move the decorator to the module scope -- it does not seem to belong inside the class. If you want to keep it inside the class, don't make it a staticmethod, but rather simply del it at the end of the class body -- it's not meant to be used from outside the class in this case.


Python classes are created at runtime, after evaluating the contents of the class declaration. The class is evaluated by assigned all declared variables and functions to a special dictionary and using that dictionary to call type.__new__ (see customizing class creation).

So,

class A(B):    c = 1

is equivalent to:

A = type.__new__("A", (B,), {"c": 1})

When you annotate a method with @staticmethod, there is some special magic that happens AFTER the class is created with type.__new__. Inside class declaration scope, the @staticmethod function is just an instance of a staticmethod object, which you can't call. The decorator probably should just be declared above the class definition in the same module OR in a separate "decorate" module (depends on how many decorators you have). In general decorators should be declared outside of a class. One notable exception is the property class (see properties). In your case having the decorator inside a class declaration might make sense if you had something like a color class:

class Color(object):    def ___init__(self, color):        self.color = color     def ensure_same_color(f):         ...black = Color("black")class TFord(object):    def __init__(self, color):        self.color = color    @black.ensure_same_color    def get():        return 'Here is your shiny new T-Ford'


Solution does exist!

Problem is that Static method that is trying to be used as decorator is in fact staticmethod object and is not callable.

Solution: staticmethod object has method __get__ which takes any argument and returns real method: python documentation Python 3.5 and up:

class StaticMethod(object):    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"    def __init__(self, f):        self.f = f    def __get__(self, obj, objtype=None):        return self.f

Min solution I came with is:

class A():    def __init__(self):        self.n =  2    @staticmethod    def _returnBaseAndResult(func):        from functools import wraps        @wraps(func)        def wrapper(*args, **kwargs):            self = args[0]            response = func(*args, **kwargs)            return self.n, response        return wrapper    @_returnBaseAndResult.__get__('this can be anything')    def square(self):        return self.n**2if __name__ == '__main__':    a = A()    print(a.square())

Will print (2, 4)