Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using python decorator with or without parentheses

In Python, what is the difference between using the same decorator with and without parentheses?

For example:

Without parentheses:

@some_decorator def some_method():     pass 

With parentheses:

@some_decorator() def some_method():     pass 
like image 266
BendEg Avatar asked Feb 23 '16 08:02

BendEg


People also ask

When should I use Python decorators?

You'll use a decorator when you need to change the behavior of a function without modifying the function itself. A few good examples are when you want to add logging, test performance, perform caching, verify permissions, and so on. You can also use one when you need to run the same code on multiple functions.

Does decorator order matter Python?

The broader answer is that it depends on what each of the decorators are doing. You need to think about the flow of your program and whether it would make logical sense for one to come before the other. Show activity on this post. You should do it like below.

Are decorators Pythonic?

Decorators are a very powerful and useful tool in Python since it allows programmers to modify the behaviour of a function or class. Decorators allow us to wrap another function in order to extend the behaviour of the wrapped function, without permanently modifying it.

Why decorators in Python are pure genius?

Decorators are a prime-time example of a perfectly implemented feature. It does take a while to wrap your head around, but it's worth it. As you start using them, you'll notice how they don't overcomplicate things and make your code neat and snazzy.


2 Answers

some_decorator in the first code snippet is a regular decorator:

@some_decorator def some_method():     pass 

is equivalent to

some_method = some_decorator(some_method) 

On the other hand, some_decorator in the second code snippet is a callable that returns a decorator:

@some_decorator() def some_method():     pass 

is equivalent to

some_method = some_decorator()(some_method) 

As pointed out by Duncan in comments, some decorators are designed to work both ways. Here's a pretty basic implementation of such decorator:

def some_decorator(arg=None):     def decorator(func):         def wrapper(*a, **ka):             return func(*a, **ka)         return wrapper      if callable(arg):         return decorator(arg) # return 'wrapper'     else:         return decorator # ... or 'decorator' 

pytest.fixture is a more complex example.

like image 151
vaultah Avatar answered Oct 19 '22 19:10

vaultah


Briefly speaking, decorators allow adding rich features to groups of functions and classes without modifying them at all.

The key to understand the difference between @some_decorator and @some_decorator() is that the former is decorator, while the latter is a function (or callable) that returns a decorator.

I believe that seeing an implementation of each case facilitates understanding the difference:

@some_decorator

def some_decorator(func):     def wrapper(func):         return func(*args, **kwargs)     return wrapper 

Application:

@some_decorator def some_method():     pass 

Equivalence:

some_method = some_decorator(some_method) 

@some_decorator()

def some_decorator():     def decorator(func):         def wrapper(*args, **kwargs):             return func(*args, **kwargs)         return wrapper     return decorator 

Application:

@some_decorator() def some_method():     pass 

Equivalence:

some_method = some_decorator()(some_method) 

Notice that now it is easier to see that @some_decorator() is a function returning a decorator while some_decorator is just a decorator. Keep in mind that some decorators are written to work both ways.

So now you might be wondering why we have these two cases when the former version seems simpler. The answer is that if you want to pass arguments to a decorator, using @some_decorator() will allow you to do this. Let's see some code in action:

def some_decorator(arg1, arg2):     def decorator(func):         def wrapper(*args, **kwargs):             print(arg1)             print(arg2)             return func(*args, **kwargs)         return wrapper     return decorator 

Application:

@some_decorator('hello', 'bye') def some_method():     pass 

Equivalence:

some_method = some_decorator('hello', 'bye')(some_method) 

Note: I think that it is worth to mention that a decorator can be implemented as a function or as a class. Check this for more information.

like image 20
lmiguelvargasf Avatar answered Oct 19 '22 21:10

lmiguelvargasf