Saqib Ali
Saqib Ali

Reputation: 12575

Python decorator works with staticmethod. But fails with 2 static methods. Why?

Here is my python code. I have a class MyClass with two static methods: my_method1 and my_method2. Both methods are wrapped with a decorator called exception_handler.

from functools import wraps
import sys

def exception_handler(function):
    @wraps(function)
    def decorator(self, *args, **kwargs):
        try:
            return function(self, *args, **kwargs)
        except Exception, e:
            print "EXCEPTION!: %s" % e
            sys.exit(-1)
    return decorator


class MyClass:
    @staticmethod
    @exception_handler
    def my_method1(a, b, c,):
        return "X"

    @staticmethod
    @exception_handler
    def my_method2(e, f, g,):
        print "Y"
        return MyClass.my_method1(a=e, b=f, c=g)

print "Trying my_method1"
print MyClass.my_method1(1, 2, 3)

print ""
print "Trying my_method2"
print MyClass.my_method2(1, 2, 3)

When I run this code, I get the following:

Trying my_method1
X

Trying my_method2
Y
EXCEPTION!: decorator() takes at least 1 argument (0 given)

Why does the decorator fail in the second instance and how can I get around it?

It seems like the decorator fails when decorated method is a static method being called by another static method. But why this would happen makes no sense to me.

Upvotes: 2

Views: 865

Answers (2)

Seif
Seif

Reputation: 1097

I think your code is failing without you noticing, can you try printing your a, b, c *args ? You will find out that a is self !!! So it fails silently by assigning the wrong arguments.

Then why it raises an exception the second call here: MyClass.my_method1(a=e, b=f, c=g) that's because your *args are empty now and self cannot replace any variable like before.

Upvotes: 0

Jared Mackey
Jared Mackey

Reputation: 4158

The problem is that staticmethods do not take self as an argument. I am not sure why it works on the first two calls and not the third. However, removing self from the decorator fixes it.

Here is the refactored code:

from functools import wraps
import sys


def exception_handler(function):
    @wraps(function)
    def decorator(*args, **kwargs):
        try:
            return function(*args, **kwargs)
        except Exception as e:
            print "EXCEPTION!: {}".format(e)
            sys.exit(-1)

    return decorator


class MyClass(object):
    @staticmethod
    @exception_handler
    def my_method1(a, b, c, ):
        return "X"

    @staticmethod
    @exception_handler
    def my_method2(e, f, g, ):
        print "Y"
        return MyClass.my_method1(a=e, b=f, c=g)


print "Trying my_method1"
print MyClass.my_method1(1, 2, 3)

print
print "Trying my_method2"
print MyClass.my_method2(1, 2, 3)

Doing so gives these results:

Trying my_method1
X

Trying my_method2
Y
X

Upvotes: 1

Related Questions