0

I am trying to implement a decorator with *args and having a few problems.

As can be seen in examples number 3 and 5, when I pass *args to the decorator the first argument is not the function (which is what I intended it to be).

My code:

from functools import partial, wraps

def decorator(func=None, *_args, **_kwargs):
    print('A:', func, _args, _kwargs)
    if not func:
        return partial(decorator, *_args, **_kwargs)

    @wraps(func)
    def wrapper(*args, **kwargs):
        print('B:', func, args, kwargs, _args, _kwargs)
        result = func(*args, **kwargs)
        print('D:', func, args, kwargs, _args, _kwargs)
        return result
    return wrapper

Testing func1:

@decorator
def func1(*args, **kwargs):
    print('C:', args, kwargs)

func1(10, 20, 30, x=40, y=50, z=60)

# Output:
# A: <function func1 at 0x7fc44e0a7ca0> () {}
# B: <function func1 at 0x7fc44e0a7ca0> (10, 20, 30) {'x': 40, 'y': 50, 'z': 60} () {}
# C: (10, 20, 30) {'x': 40, 'y': 50, 'z': 60}
# D: <function func1 at 0x7fc44e0a7ca0> (10, 20, 30) {'x': 40, 'y': 50, 'z': 60} () {}

Testing func2:

@decorator()
def func2(*args, **kwargs):
    print('C:', args, kwargs)

func2(10, 20, 30, x=40, y=50, z=60)

# Output:
# A: None () {}
# A: <function func2 at 0x7fc44e0a79d0> () {}
# B: <function func2 at 0x7fc44e0a79d0> (10, 20, 30) {'x': 40, 'y': 50, 'z': 60} () {}
# C: (10, 20, 30) {'x': 40, 'y': 50, 'z': 60}
# D: <function func2 at 0x7fc44e0a79d0> (10, 20, 30) {'x': 40, 'y': 50, 'z': 60} () {}

Testing func3:

@decorator(1, 2, 3)
def func3(*args, **kwargs):
    print('C', args, kwargs)

func3(10, 20, 30, x=40, y=50, z=60)

# Output:
# A: 1 (2, 3) {}
# B: 1 (<function func3 at 0x7fc44e001af0>,) {} (2, 3) {}
# TypeError: 'int' object is not callable

Testing func4:

@decorator(a=1, b=2, c=3)
def func4(*args, **kwargs):
    print('C:', args, kwargs)

func4(10, 20, 30, x=40, y=50, z=60)

# Output:
# A: None () {'a': 1, 'b': 2, 'c': 3}
# A: <function func4 at 0x7fc44e0015e0> () {'a': 1, 'b': 2, 'c': 3}
# B: <function func4 at 0x7fc44e0015e0> (10, 20, 30) {'x': 40, 'y': 50, 'z': 60} () {'a': 1, 'b': 2, 'c': 3}
# C: (10, 20, 30) {'x': 40, 'y': 50, 'z': 60}
# D: <function func4 at 0x7fc44e0015e0> (10, 20, 30) {'x': 40, 'y': 50, 'z': 60} () {'a': 1, 'b': 2, 'c': 3}

Testing func5

@decorator(1, 2, 3, a=1, b=2, c=3)
def func5(*args, **kwargs):
    print('C:', args, kwargs)

func5(10, 20, 30, x=40, y=50, z=60)

# Output:
# A: 1 (2, 3) {'a': 1, 'b': 2, 'c': 3}
# B: 1 (<function func5 at 0x7fc44e0014c0>,) {} (2, 3) {'a': 1, 'b': 2, 'c': 3}
# TypeError: 'int' object is not callable
Idan Hazan
  • 76
  • 9

0 Answers0