Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build a decorator with optional parameters? [duplicate]

I would like to make a decorator which could be used with or without a parameter : Something like this :

class d(object):     def __init__(self,msg='my default message'):         self.msg = msg     def __call__(self,fn):         def newfn():             print self.msg             return fn()         return newfn  @d('This is working') def hello():     print 'hello world !'  @d def too_bad():     print 'does not work' 

In my code, only the use of decorator with parameter is working: How to proceed to have both working (with and without parameter)?

like image 517
Eric Avatar asked Oct 14 '10 09:10

Eric


People also ask

How do we create optional parameter?

By Params Keyword: You can implement optional parameters by using the params keyword. It allows you to pass any variable number of parameters to a method. But you can use the params keyword for only one parameter and that parameter is the last parameter of the method.

Can a function with parameters be decorated?

The syntax for decorators with parameters : Inside the inner function, required operations are performed and the actual function reference is returned which will be assigned to func_name. Now, func_name() can be used to call the function with decorator applied on it.

Can a function have 2 decorators?

So, here in this post, we are going to learn about Decorator Chaining. Chaining decorators means applying more than one decorator inside a function. Python allows us to implement more than one decorator to a function.

Can decorator take arguments Python?

Implementing Decorator Arguments You may expect that decorator arguments are somehow passed into the function along with this f argument, but sadly Python always passes the decorated function as a single argument to the decorator function.


2 Answers

I found an example, you can use @trace or @trace('msg1','msg2'): nice!

def trace(*args):     def _trace(func):         def wrapper(*args, **kwargs):             print enter_string             func(*args, **kwargs)             print exit_string         return wrapper     if len(args) == 1 and callable(args[0]):         # No arguments, this is the decorator         # Set default values for the arguments         enter_string = 'entering'         exit_string = 'exiting'         return _trace(args[0])     else:         # This is just returning the decorator         enter_string, exit_string = args         return _trace 
like image 200
Eric Avatar answered Oct 11 '22 12:10

Eric


If you want to take parameters to your decorator, you need to always call it as a function:

@d() def func():     pass 

Otherwise, you need to try to detect the difference in parameters--in other words, you need to magically guess what the caller means. Don't create an API that needs to guess; consistently say what you mean to begin with.

In other words, a function should either be a decorator, or a decorator factory; it shouldn't be both.

Note that if all you want to do is store a value, you don't need to write a class.

def d(msg='my default message'):     def decorator(func):         def newfn():             print msg             return func()         return newfn     return decorator  @d('This is working') def hello():     print 'hello world !'  @d() def hello2():     print 'also hello world' 
like image 31
Glenn Maynard Avatar answered Oct 11 '22 13:10

Glenn Maynard