Make the first argument for wrap_function
the number of repeats with the default value of max_repeats
specified in the decorator.
def decorator_wraper(max_repeats = 20): def decorator(function): def wrap_function(max_repeating = max_repeats, * args, ** kwargs): print(f "max_repeating = {max_repeating}") repeat = 0 while repeat < max_repeating: try: return function( * args, ** kwargs) except Exception: pass return wrap_function return decorator @decorator_wraper(5) def decorate_me_with_argument(): print('decorate_me_with_argument') @decorator_wraper() def decorate_me_with_default(): print('decorate_me_with_default') decorate_me_with_argument() # max_repeating = 5 decorate_me_with_default() # max_repeating = 20 decorate_me_with_argument(3) # max_repeating = 3 decorate_me_with_default(8) # max_repeating = 8
The other way to do this is to expose the number of repeats on the wrap_function
:
def decorator_wrapper(max_repeating = 20):
def decorator(function):
def wrap_function( * args, ** kwargs):
print(f "max_repeating = {wrap_function.max_repeating}")
for _ in range(wrap_function.max_repeating):
try:
return function( * args, ** kwargs)
except Exception:
pass
wrap_function.max_repeating = max_repeating
return wrap_function
return decorator
That way you don't change the interface of the wrapped function
, but you can still change the repeat limit after the initial decoration:
>>> @decorator_wrapper()
...def bad_func():
...print("in bad func")
...raise Exception("oh no!")
...
>>>
bad_func.max_repeating
20
>>>
bad_func.max_repeating = 3 >>>
bad_func()
max_repeating = 3 in bad func in bad func in bad func
Adding arbitrary attributes to wrap_function
would also allow you to provide an inline API for calling the wrapped function with a different number of retries, e.g. something like:
bad_func.retry_times(3)()
Following is similar to what I have in my project, the kwargs
param takes all what are passed from the decorated function:
def decorator_wraper(func):
def wrap_function(max_repeating = 20, * args, ** kwargs):
if kwargs.get('max_repeating'):
max_repeating = kwargs['max_repeating']
print(max_repeating)
# TODO
return func( * args, ** kwargs)
return wrap_function
@decorator_wraper
def decorate_me():
pass
decorate_me() # should print 20
decorate_me(max_repeating = 10) # should print 10
Last Updated : 17 Nov, 2021,GATE CS 2021 Syllabus
The syntax for decorators with parameters :
@decorator(params)
def func_name():
''
' Function implementation'
''
The above code is equivalent to
def func_name():
''
' Function implementation'
''
func_name = (decorator(params))(func_name)
""
"
Output:
Inside decorator
Inside inner
function
Decorated the
function
Inside actual
function
Output:
I like Geeksforgeeks
Summation of values - 27
Geeks
for
Geeks
Output:
Decorator
for 'stringJoin'
Decorator
for 'summation'
stringJoin started...
I like Geeksforgeeks
summation started...
1729
Summary: in this tutorial, you’ll learn how to define Python decorators with arguments using a decorator factory.,Use a factory decorator to return a decorator that accepts arguments.,To define the repeat decorator, the repeat(5) should return the original decorator.,In this code, the decorate function is a decorator. It’s equivalent to the original repeat decorator.
Suppose that you have a function called say
that prints out a message:
.wp - block - code { border: 0; padding: 0; } .wp - block - code > div { overflow: auto; } .shcb - language { border: 0; clip: rect(1 px, 1 px, 1 px, 1 px); - webkit - clip - path: inset(50 % ); clip - path: inset(50 % ); height: 1 px; margin: -1 px; overflow: hidden; padding: 0; position: absolute; width: 1 px; word - wrap: normal; word - break: normal; } .hljs { box - sizing: border - box; } .hljs.shcb - code - table { display: table; width: 100 % ; } .hljs.shcb - code - table > .shcb - loc { color: inherit; display: table - row; width: 100 % ; } .hljs.shcb - code - table.shcb - loc > span { display: table - cell; } .wp - block - code code.hljs: not(.shcb - wrap - lines) { white - space: pre; } .wp - block - code code.hljs.shcb - wrap - lines { white - space: pre - wrap; } .hljs.shcb - line - numbers { border - spacing: 0; counter - reset: line; } .hljs.shcb - line - numbers > .shcb - loc { counter - increment: line; } .hljs.shcb - line - numbers.shcb - loc > span { padding - left: 0.75 em; } .hljs.shcb - line - numbers.shcb - loc::before { border - right: 1 px solid #ddd; content: counter(line); display: table - cell; padding: 0 0.75 em; text - align: right; - webkit - user - select: none; - moz - user - select: none; - ms - user - select: none; user - select: none; white - space: nowrap; width: 1 % ; } def say(message): '' ' print the message Arguments message: the message to show '' ' print(message) Code language: Python(python)
and you want to execute the say()
function 5 times repeatedly each time you call it. For example:
say('Hi') Code language: Python(python)
It should show the following the Hi
message five times as follows:
Hi Hi Hi Hi Hi
And you can define the repeat
decorator as follows:
def repeat(fn):
@wraps(fn)
def wrapper( * args, ** kwargs):
for _ in range(5):
result = fn( * args, ** kwargs)
return result
return wrapper Code language: Python(python)
The following shows the complete code:
from functools import wraps def repeat(fn): @wraps(fn) def wrapper( * args, ** kwargs): for _ in range(5): result = fn( * args, ** kwargs) return result return wrapper @repeat def say(message): '' ' print the message Arguments message: the message to show '' ' print(message) say('Hello') Code language: Python(python)
Joined Jul 9, 2018 , Sahil - Jul 31 , Joined Jul 20, 2017 , Joined May 30, 2018
[1]: def outer_function():
...: print "1. This is outer function!"
...: def inner_function():
...: print "2. This is inner function, inside outer function!"
...: print "3. This is outside inner function, inside outer function!"
...: return inner_function()
...:
[2]: func_assign = outer_function()
1. This is outer
function !
3. This is outside inner
function, inside outer
function !
2. This is inner
function, inside outer
function !
import time
def timetest(input_func):
def timed( * args, ** kwargs):
start_time = time.time()
result = input_func( * args, ** kwargs)
end_time = time.time()
print "Method Name - {0}, Args - {1}, Kwargs - {2}, Execution Time - {3}".format(
input_func.__name__,
args,
kwargs,
end_time - start_time
)
return result
return timed
@timetest
def foobar( * args, ** kwargs):
time.sleep(0.3)
print "inside foobar"
print args, kwargs
foobar(["hello, world"], foo = 2, bar = 5)
inside foobar
(['hello, world'], ) {
'foo': 2,
'bar': 5
}
Method Name - foobar, Args - (['hello, world'], ), Kwargs - {
'foo': 2,
'bar': 5
}, Execution Time - 0.30296087265
def method_decorator(method):
def inner(city_instance):
if city_instance.name == "SFO":
print "Its a cool place to live in."
else:
method(city_instance)
return inner
class City(object):
def __init__(self, name):
self.name = name
@method_decorator
def print_test(self):
print self.name
p1 = City("SFO")
p1.print_test()
Its a cool place to live in .
class decoclass(object):
def __init__(self, f):
self.f = f
def __call__(self, * args, ** kwargs):
# before f actions
print 'decorator initialised'
self.f( * args, ** kwargs)
print 'decorator terminated'
# after f actions
@decoclass
def klass():
print 'class'
klass()
def makebold(f):
return lambda: "<b>" + f() + "</b>"
def makeitalic(f):
return lambda: "<i>" + f() + "</i>"
@makebold
@makeitalic
def say():
return "Hello"
print say()
def decorator(func):
""
"decorator docstring"
""
def inner_function( * args, ** kwargs):
""
"inner function docstring "
""
print func.__name__ + "was called"
return func( * args, ** kwargs)
return inner_function
@decorator
def foobar(x):
""
"foobar docstring"
""
return x ** 2
last modified July 29, 2022
#!/usr/bin/python
def enclose(fun):
def wrapper():
print("***************************")
fun()
print("***************************")
return wrapper
def myfun():
print("myfun")
enc = enclose(myfun)
enc()
The enclose
function is a decorator which extends the decorated
function by adding star symbols to its output.
def enclose(fun): ...
The enclose
function takes a function as a parameter.
def wrapper():
print("***************************")
fun()
print("***************************")
return wrapper
This is a regular function to be decorated.
enc = enclose(myfun) enc()
The myfun
is passed to the enclose
function, in
which it is extended. The wrapper function is returned and called.
$. / enclose.py **
** ** ** ** ** ** ** ** ** ** ** ** *
myfun **
** ** ** ** ** ** ** ** ** ** ** ** *
#8 Mansour said 2021-07-24T06:43:19Z
While there are many valid use cases that can be solved with the decorators that you learned in the previous parts of this series, there are some situations in which arguments come in handy. Consider the famous app.route
decorator from Flask, as an example:
@app.route('/foo')
def foo():
return 'this is the foo route'
Unfortunately adding arguments to a decorator is far from trivial. Let's revisit the standard decorator structure we have used so far:
def my_decorator(f):
def wrapped( * args, ** kwargs):
print('before function')
response = f( * args, ** kwargs)
print('after function')
return response
print('decorating', f)
return wrapped
@my_decorator
def my_function(a, b):
print('in function')
return a + b
Let's call the decorators that we've seen until now "standard decorators". We've seen that a standard decorator is a function that takes the decorated function as an argument and returns another function that takes its place. Using the above my_function()
example, the work that the standard decorator does can be described also in Python as:
my_function = my_decorator(my_function)
Here is an example usage for this decorator:
@my_decorator('foo')
def my_function(a, b):
print('in function')
return a + b
The equivalent Python expression for this new decorator is:
my_function = my_decorator('foo')(my_function)
As i never had a time to explore it deep my self.
Really appreciate it!
Thanks Miguel,
Best regards,
Domas Zelionis
Hello Miguel,
I just wanted to say this series is awesome!
And I like the way you explain things in the simplest manner and also pragmatic way by covering different aspects of flask things!
Rock on!
Great explanations.Thanks!
Good explanation!!Keep sharing the knowledge!!
Why no mention of functools.wrap in this article series ? It removes a lot of the boiler plate