python decorator TypeError missing 1 required positional argument
Understand what decorator is:
@exponential_backoff
def test():
pass
equals to:
def test():
pass
test = exponential_backoff(test)
In this case, test
is def our_decorator(func):
. That's why you get TypeError
when calling test()
.
So further:
@exponential_backoff()
def test():
pass
equals to:
def test():
pass
test = exponential_backoff()(test)
In this case, now test
is what you need.
Further, functools.wraps
helps you to copy all properties of original function to decorated function. Such as function's name or docstring:
from functools import wraps
def exponential_backoff(func):
# @wraps(func)
def function_wrapper(*args, **kwargs):
pass
return function_wrapper
@exponential_backoff
def test():
pass
print(test) # <function exponential_backoff.<locals>.function_wrapper at 0x7fcc343a4268>
# uncomment `@wraps(func)` line:
print(test) # <function test at 0x7fcc343a4400>
You should be using:
@exponential_backoff()
def test():
...
The overall decorator is not designed to have arguments be optional, so you must provide ()
when using it.
If want an example of how to make decorator allow argument list be optional, see:
- https://wrapt.readthedocs.io/en/latest/decorators.html#decorators-with-optional-arguments
You might also consider using the wrapt package to make your decorators easier and more robust.
Either you go for the solution provided by @Graham Dumpleton or you can just modify your decorator like so:
from functools import wraps, partial
def exponential_backoff(func=None, seconds=10, attempts=10):
if func is None:
return partial(exponential_backoff, seconds=seconds, attempts=attempts)
@wraps(func)
def function_wrapper(*args, **kwargs):
for s in range(0, seconds*attempts, attempts):
sleep(s)
try:
return func(*args, **kwargs)
except Exception as e:
print(e)
return function_wrapper
@exponential_backoff
def test():
for a in range(100):
if a - random.randint(0,1) == 0:
print('success count: {}'.format(a))
pass
else:
print('error count {}'.format(a))
'a' + 1
test()
EDIT My answer was not entirely correct, please see @GrahamDumpleton's answer which shows how to make my attempt of a solution viable (i.e. this link). Fixed it now, thank you @GrahamDumpleton !