0

This question is related to another question I just asked.

I have created a python decorator as shown below. I want this decorator to accept an unknown list of arguments. But there is an added wrinkle. The decorator is an instance method of another class:

#!/usr/bin/env python
from functools import wraps


class A:

    def my_decorator(self, func=None, **kwargs):

        def inner_function(decorated_function):

            def wrapped_func(*fargs, **fkwargs):
                print kwargs
                return decorated_function(*fargs, **fkwargs)
            return wrapped_func

        if func:
            return inner_function(func)
        else:
            return inner_function

class B:
    my_a = A()

    @my_a.my_decorator(arg_1="Yolo", arg2="Bolo")
    def my_func():
         print "Woo Hoo!"


my_B = B()
B.my_func()

But this code below doesn't work:

Traceback (most recent call last):
  File "./decorator_test.py", line 30, in <module>
    B.my_func()
TypeError: unbound method wrapped_func() must be called with B instance as first argument (got nothing instead)

How to fix it?

Saqib Ali
  • 11,931
  • 41
  • 133
  • 272
  • Did you forget `@staticmethod`, here? Because `my_func()` is a method of `B` and requires an object to be invoked. It's also missing the `self` parameter. Or should that be `my_B.my_func()` (in that case `self` is still missing, though). – dhke Jun 06 '17 at 19:02
  • I meant `my_B.my_func()`. Sorry. I fixed typos and now it is working. – Saqib Ali Jun 06 '17 at 19:11

1 Answers1

0

Here's my approach to coding your decorator:

class A:
    def __init__(self, func=None, **kargs):
        self.args  = func
        self.kargs = kargs 
    def __call__(self, decorated_function): 
        def wrapper_func(*args, **kargs):
            print kargs
            return decorated_function(*args, **kwargs)
        if self.func:
            #..do something..
            return wrapper_func
        elif 'xyz' in self.kargs:
            #...do something else here..
            return wrapper_func
        else:
            ...


class B:
    @A(arg_1="Yolo", arg2="Bolo")              # A(...)(my_func)
    def my_func():
        print "Woo Hoo!"

This is a typical way of coding decorators. Class A returns a callable object when called. The callable object of class A will be called automatically for decoration. When the callable object is called, its __call__ method gets triggered and its __call__ operator overloading method returns the wrapper function after performing some customization. The wrapper function is the function that wraps logic around your original function.

GIZ
  • 4,409
  • 1
  • 24
  • 43