1

For better encapsulation, I want to decorate instance methods with methods inside the same class.

class SomeClass(object):

    @staticmethod
    def some_decorator(func):
        def wrapped(self):
            print 'hello'
            return func(self)
        return wrapped

    @some_decorator
    def do(self):
        print 'world'

x = SomeClass()
x.do()

However, this piece of code raises TypeError: 'staticmethod' object is not callable

Now I make a workaround by defining a class and overload its new method to simulate a function, but it's eventually a class, not a function.

So can I access my functions inside the class scope?

zstbsqx
  • 60
  • 8
  • 1
    Possible duplicate of [Python decorator as a staticmethod](http://stackoverflow.com/questions/6412146/python-decorator-as-a-staticmethod) – julienc Apr 27 '17 at 09:19

1 Answers1

2

Just get rid of that @staticmethod line. You want some_decorator to behave like a plain function, not like some kind of method.

The decorator is called when the class definition is being executed, before the class object itself exists. The normal method definitions inside a class are actually just plain old functions, they become methods dynamically each time they are called as attributes of the class instance (which turns them into bound methods). But while the class object itself is being built you can treat them as plain functions.

class SomeClass(object):
    def some_decorator(func):
        def wrapped(self):
            print 'hello'
            return func(self)
        return wrapped

    @some_decorator
    def do(self):
        print 'world'

x = SomeClass()
x.do()

output

hello
world

BTW, you have an error in your decorator: it's returning wrapped() instead of wrapped.


As chepner mentions in the comments we can delete some_decorator so that it doesn't take up space in the class object after we've finished using it in the class definition. (If we accidentally try to call it we'll get an error). We could do del SomeClass.some_decorator after the class definition, but it's also perfectly valid to put a del statement inside the class definition:

class SomeClass(object):
    def some_decorator(func):
        def wrapped(self):
            print 'hello'
            return func(self)
        return wrapped

    @some_decorator
    def do(self):
        print 'world'

    del some_decorator
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
  • 1
    You can add `del some_decorator` to the end of the class definition if you don't want to clutter your class's namespace. You don't need it anymore after `do` is defined. – chepner Apr 28 '17 at 03:05
  • @chepner Good point. I originally didn't bother, since it's pretty hard to call it outside the class definition without raising `TypeError`, but I guess it's cleaner to get rid of it. – PM 2Ring Apr 28 '17 at 03:32