Assuming module foo
with method bar
:
import foo
method_to_call = getattr(foo, 'bar')
result = method_to_call()
You could shorten lines 2 and 3 to:
result = getattr(foo, 'bar')()
if that makes more sense for your use case.
You can use getattr
in this fashion on class instance bound methods, module-level methods, class methods... the list goes on.
Given a list of lists t
,
flat_list = [item for sublist in t for item in sublist]
which means:
flat_list = []
for sublist in t:
for item in sublist:
flat_list.append(item)
is faster than the shortcuts posted so far. (t
is the list to flatten.)
Here is the corresponding function:
def flatten(t):
return [item for sublist in t for item in sublist]
As evidence, you can use the timeit
module in the standard library:
$ python -mtimeit -s't=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in t for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s't=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(t, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s't=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,t)'
1000 loops, best of 3: 1.1 msec per loop
Explanation: the shortcuts based on +
(including the implied use in sum
) are, of necessity, O(T**2)
when there are T sublists -- as the intermediate result list keeps getting longer, at each step a new intermediate result list object gets allocated, and all the items in the previous intermediate result must be copied over (as well as a few new ones added at the end). So, for simplicity and without actual loss of generality, say you have T sublists of k items each: the first k items are copied back and forth T-1 times, the second k items T-2 times, and so on; total number of copies is k times the sum of x for x from 1 to T excluded, i.e., k * (T**2)/2
.
The list comprehension just generates one list, once, and copies each item over (from its original place of residence to the result list) also exactly once.
Best Answer
If you are not into long explanations, see Paolo Bergantino’s answer.
Decorator Basics
Python’s functions are objects
To understand decorators, you must first understand that functions are objects in Python. This has important consequences. Let’s see why with a simple example :
Keep this in mind. We’ll circle back to it shortly.
Another interesting property of Python functions is they can be defined inside another function!
Functions references
Okay, still here? Now the fun part...
You’ve seen that functions are objects. Therefore, functions:
That means that a function can
return
another function.There’s more!
If you can
return
a function, you can pass one as a parameter:Well, you just have everything needed to understand decorators. You see, decorators are “wrappers”, which means that they let you execute code before and after the function they decorate without modifying the function itself.
Handcrafted decorators
How you’d do it manually:
Now, you probably want that every time you call
a_stand_alone_function
,a_stand_alone_function_decorated
is called instead. That’s easy, just overwritea_stand_alone_function
with the function returned bymy_shiny_new_decorator
:Decorators demystified
The previous example, using the decorator syntax:
Yes, that’s all, it’s that simple.
@decorator
is just a shortcut to:Decorators are just a pythonic variant of the decorator design pattern. There are several classic design patterns embedded in Python to ease development (like iterators).
Of course, you can accumulate decorators:
Using the Python decorator syntax:
The order you set the decorators MATTERS:
Now: to answer the question...
As a conclusion, you can easily see how to answer the question:
You can now just leave happy, or burn your brain a little bit more and see advanced uses of decorators.
Taking decorators to the next level
Passing arguments to the decorated function
Decorating methods
One nifty thing about Python is that methods and functions are really the same. The only difference is that methods expect that their first argument is a reference to the current object (
self
).That means you can build a decorator for methods the same way! Just remember to take
self
into consideration:If you’re making general-purpose decorator--one you’ll apply to any function or method, no matter its arguments--then just use
*args, **kwargs
:Passing arguments to the decorator
Great, now what would you say about passing arguments to the decorator itself?
This can get somewhat twisted, since a decorator must accept a function as an argument. Therefore, you cannot pass the decorated function’s arguments directly to the decorator.
Before rushing to the solution, let’s write a little reminder:
It’s exactly the same. "
my_decorator
" is called. So when you@my_decorator
, you are telling Python to call the function 'labelled by the variable "my_decorator
"'.This is important! The label you give can point directly to the decorator—or not.
Let’s get evil. ☺
No surprise here.
Let’s do EXACTLY the same thing, but skip all the pesky intermediate variables:
Let’s make it even shorter:
Hey, did you see that? We used a function call with the "
@
" syntax! :-)So, back to decorators with arguments. If we can use functions to generate the decorator on the fly, we can pass arguments to that function, right?
Here it is: a decorator with arguments. Arguments can be set as variable:
As you can see, you can pass arguments to the decorator like any function using this trick. You can even use
*args, **kwargs
if you wish. But remember decorators are called only once. Just when Python imports the script. You can't dynamically set the arguments afterwards. When you do "import x", the function is already decorated, so you can't change anything.Let’s practice: decorating a decorator
Okay, as a bonus, I'll give you a snippet to make any decorator accept generically any argument. After all, in order to accept arguments, we created our decorator using another function.
We wrapped the decorator.
Anything else we saw recently that wrapped function?
Oh yes, decorators!
Let’s have some fun and write a decorator for the decorators:
It can be used as follows:
I know, the last time you had this feeling, it was after listening a guy saying: "before understanding recursion, you must first understand recursion". But now, don't you feel good about mastering this?
Best practices: decorators
The
functools
module was introduced in Python 2.5. It includes the functionfunctools.wraps()
, which copies the name, module, and docstring of the decorated function to its wrapper.(Fun fact:
functools.wraps()
is a decorator! ☺)How can the decorators be useful?
Now the big question: What can I use decorators for?
Seem cool and powerful, but a practical example would be great. Well, there are 1000 possibilities. Classic uses are extending a function behavior from an external lib (you can't modify it), or for debugging (you don't want to modify it because it’s temporary).
You can use them to extend several functions in a DRY’s way, like so:
Of course the good thing with decorators is that you can use them right away on almost anything without rewriting. DRY, I said:
Python itself provides several decorators:
property
,staticmethod
, etc.This really is a large playground.