#decorators in Python: why the inner defined function? - python

I'm just starting with Python and I have just been exposed to decorators. I wrote the following code, mimicking what I am seeing, and it works:
def decorator_function(passed_function):
def inner_decorator():
print('this happens before')
passed_function()
print('this happens after')
return inner_decorator
#decorator_function
def what_we_call():
print('The actual function we called.')
what_we_call()
But then I wrote this, which throws errors:
def decorator_function(passed_function):
print('this happens before')
passed_function()
print('this happens after')
#decorator_function
def what_we_call():
print('The actual function we called.')
what_we_call()
So, why do we need to have that inner nested function inside the decorator function? what purpose does it serve? Wouldn't it be simpler to just use the syntax of the second? What am I not getting?
The funny thing is that BOTH have the same (correct) output, but the second on has error text as well, saying "TypeError: 'NoneType' object is not callable"
Please use language and examples suitable for someone just starting with Python, his first programming language - and also new to OOP as well! :) Thanks.

The reason is that when you wrap what_we_call in decorator_function by doing:
#decorator_function
def what_we_call():
...
What you're doing is:
what_we_call = decorator_function(what_we_call)
In you first example it works because you don't run the inner_function actually, you only initialise it, and then you return the new inner_function back (that you will call later when call the decorated what_we_call):
def decorator_function(passed_function):
def inner_decorator():
print('this happens before')
passed_function()
print('this happens after')
return inner_decorator
Contrarily, in your second example you're going to run 2 print statements and the passed_function (what_we_call in our case) in the between:
def decorator_function(passed_function):
print('this happens before')
passed_function()
print('this happens after')
In other words, you don't return a function in the example of before:
what_we_call = decorator_function(what_we_call)
You run the code (and you see the output), but then decorator_function returns 'None' to what_we_call (overwriting the original function), and when you call 'None' as if it was a function Python complains.

Python decorators are basically just syntactic sugar. This:
#decorator
def fn(arg1, arg2):
return arg1 + arg2
Becomes this:
def fn(arg1, arg2):
return arg1 + arg2
fn = decorator(fn)
That is, a decorator basically accepts a function as an argument, and returns "something"; that "something" is bound to the name of the decorated function.
In nearly all cases, that "something" should be another function, because it is expected that fn will be a function (and will probably be called as though it is).

Related

Decorator execution?

Playing with decorator, founds something strange: I have something simple as below (a decorator to register the function to a list:
stored_f = []
def register(f):
stored_f.append(f.__name__)
return f
#register
def say_hello(name):
print(f"Hello {name}")
#register
def ur_awesome(name):
return f"{name}, you are awesome!"
I thought the above code will do nothing (it will print nothing out), because I haven't executed anything, but actually a print command "print(stored_f)" will have a output:
['say_hello', 'ur_awesome']
Meaning the line "stored_f.append(f.__name__)" in register() actually got executed, twice. This is weird to me.
I tried to define a wrapper() inside register like normally and then return wrapper, the issue will go away. But still I don't understand why the above code will partially execute the decorator without calling it.
Importing and running a Python file executes it and adding the decorator with #register executes the decorator.
So, even though your script only consists of the variable declaration, the decorator and two function definitions, when you run it, both those definitions will be executed (defining the functions) and decorator functions on them will be executed, so that the functions are correctly decorated.
Added after your comment: consider this:
stored_f = []
def register(f):
stored_f.append(f.__name__)
print('it runs!')
return f
#register
def say_hello(name):
print(f"Hello {name}")
#register
def ur_awesome(name):
return f"{name}, you are awesome!"
You'll find that, if you run this script, the output is:
it runs!
it runs!
All the code in the decorator runs and you just return the same function it received, so f will work just the same before and after.
Also, if you add say_hello("john") to the end of that script, you'll find the decorator does not run again, only the function runs again.
Also, compare this:
stored_f = []
def register(f):
stored_f.append(f.__name__)
def decorated_f(*args):
print('it runs!')
f(*args)
return decorated_f
#register
def say_hello(name):
print(f"Hello {name}")
say_hello("john")
say_hello("pete")
This results in:
it runs!
Hello john
it runs!
Hello pete
Perhaps that's closer to what you were expecting. Note that the decorator doesn't return the original function, it returns the new one.
Based on Grimar's answer, I did the following, may explain it from another angle, at least to myself:
def do_twice(f):
print('This will be executed anyway')
def wrapper():
f()
f()
return wrapper
#do_twice
def say_hello():
print('This is say hello')
output:
This will be executed anyway
if I run:
say_hello()
output:
This is say hello
This is say hello

Python inner functions/decorators: When should I use parentheses when returning an inner function?

I am learning about Python decorators and inner functions and have some questions about the lesson I'm learning via a YouTube video from codeacademy.com https://youtu.be/WOHsHaaJ8VQ.
When using inner functions sometimes I have to return the function with parenthesis, and sometimes without.
If I call an inner function without using decorators, I have to use parentheses when returning the inner function, otherwise it seems the inner function is returned as an object(?).
In the YouTube video from codeacademy.com as well as this one https://www.youtube.com/watch?v=FsAPt_9Bf3U, they call the inner function without parentheses and the expected result is output.
If I call an inner function using decorators, I have to not use parentheses when returning the inner function, otherwise it seems to work correctly, but throws an error along with some other weird results.
I've written some code to test different variations and output the results.
You can see the live code here: https://trinket.io/python/af1b47658f
# Test 1: The title function returns inner function wrapper without parentheses.
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper # Without parentheses
def print_my_name():
print("John")
print('Test 1')
title(print_my_name)
# Results: Nothing is printed.
# Test 2: The title function returns inner function wrapper with parentheses.
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper() # With parentheses
def print_my_name():
print("John")
print('Test 2')
title(print_my_name)
# Results: Professor John is printed.
# Test 3: Using a decorator while the title function returns inner function wrapper without parentheses
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper # Without parentheses
#title
def print_my_name():
print("John")
print('Test 3')
print_my_name()
# Results: Professor John is printed.
# Test 4: Using a decorator while the title function returns inner function wrapper with parentheses
def title(print_name_function):
def wrapper():
print("Professor:")
print_name_function()
return wrapper() # With parentheses
#title
def print_my_name():
print("John")
print('Test 4')
print_my_name()
# Results: Professor John is printed and the following error is thrown:
'''
Traceback (most recent call last):
File "decorators.py", line 59, in <module>
print_my_name()
TypeError: 'NoneType' object is not callable.
'''
# Additionally, Professor John is printed before 'Test 4' is printed which seems that print_my_name() runs, then print('Test 4') runs.
In the two videos I've watched listed above about inner functions/decorators I've found...
For inner functions: the inner function was returned without using parentheses and ran correctly. Upon my testing, I have to use the parentheses for it to run correctly.
For decorators: the inner function was returned without using parentheses and ran correctly. Upon my testing, running without using parentheses works. Running with parentheses seems to work, but the output order is mixed up and an error is thrown (see test 4 in my code).
Let's break this down into two parts.
1) Let's ignore decorators for now.
You should use parentheses when you want to call some function.
Without parentheses, a function is just its name.
For example:
Here is a function, where we give it a number, and we get back that number plus 5.
def add_five(x):
return x + 5
We see that add_five, without parentheses, is just the function definition. Think of it as a recipe. It's not the actually cake, just the instructions on how to bake a cake.
>>> add_five
<function add_five at 0x10da3ce18>
Now we give it an ingredient, and it makes a cake:
>>> add_five(1)
6
Let's do a similar thing, but with better names.
>>> def make_cake(cake_type):
>>> print("Making: " + cake_type + " cake!")
>>> make_cake("carrot")
'Making: carrot cake!'
>>> make_cake
<function make_cake at 0x10da3cf28>
Ok, so when we put the function name without any parentheses, we're not actually calling the function, we're just getting the declaration of the function (which is kinda like the function's Birth Certificate, which has its memory address, in this case: 0x10da3cf28.
The same thing applies for functions that don't expect any parameters.
Without the parentheses, you're just asking, "Hey function, you exist?"
With the parentheses (and necessary parameters/variables required), you're saying, "Hey function, do something!"
Now for the second part.
2) What do Decorators do?
#SyntaxVoid has a great explanation about what you're doing. Decorators are a much more complicated thing, so I'll stick to explaining what they're doing in this specific context.
Basically, your decorator, #<Some Function Name> specifies a function to call the decorated function on.
def some_decorator(function_that_I_decorated):
print("I'm going to print this, and then call my decorated function!")
function_that_I_decorated()
#some_decorator
def my_decorated_function():
print("Did I do anything?")
Then we see the results:
>>> def some_decorator(function_that_I_decorated):
... print("I'm going to print this, and then call my decorated function!")
... function_that_I_decorated()
...
>>> #some_decorator
... def my_decorated_function():
... print("Did I do anything?")
...
I'm going to print this, and then call my decorated function!
Did I do anything?
Now here's the important part:
>>> my_decorated_function
>>> my_decorated_function()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
Wait... didn't we define my_decorated_function?
Yes, we defined the function, but the decorator is reassigning that function name to something else.
Namely, my_decorator_function = some_decorator(my_decorator_function)
Now some_decorator happens to do something before calling my_decorator_function. It prints some stuff. But what is the return value of some_decorator? There's no return statement, so some_decorator returns None by default.
Therefore, my_decorator_function was created, run, and now has a new value.
Why would we want this behavior?
When we want the output to change, when running the same function with the same input(s) multiple times.
For example, maybe I want a function that returns "Go Left" every other time it's called, or "Go Right" every 5-times the function gets called.
If I want to do this with a function with more than one variable, that's easy! Just pass it in and check if num_times == whatever_int.
But life ain't so easy- sometimes other people already have functions written that are much simpler and only allow one variable, because that's more generalizable. Or maybe it's so complex it would take us a really long time to figure out how the function works (and we usually don't want to violate abstraction barriers anyways). In those situations, we need to adapt their function to our needs.
I would encourage you to read more about Currying, as that'll help you understand other uses too.
Let me use this famous quote first.
In python everything is an object.
I've been wrapping my head about two hours, until I remembered this quote. We should think original function and decorated function as objects, given an example:
def decorator(original_func):
def decorated_func():
print("Start decoration")
original_func()
print("End decoration")
return decorated_func # return decorated function as object without calling
#decorator
def func():
print("I will be decorated")
func()
The decorator_func transfers the func object to decorated_func object, and return the decorated_func as an object, so when we call func object with it's original name, we are actually calling the new function object decorated_func, which is equivalent to decorated_func().
Now it is easy to see why return decorated_func() is wrong, if we return decorated_func() in definition of decorator, we are return None, because the default return value of a function is None, and None is not callable as traceback says, so we can't use func() to call func.
Additionally, although the following two codes are equivalent, decorator help us to simplify our code, and without changing the original function object, also don't need to create a new function object mannually
#decorator
def func():
print("I will be decorated")
func()
def func():
print("I will be decorated")
dec_func = decorator(func)
dec_func()

Python decorator - Trying to understand a simple example

I am trying to understand python decorators.
I devised that simple example where I want the decorator function to be a custom log that just print error if for instance I try to sum_ and int and a str
def log(fun):
try:
return fun(*args)
except:
print('error!')
#log
def sum_(a,b):
return a+b
This returns "error" already simply when I define the function. I suspect there are multiple wrong things in what I did... I tried to look into the other questions about that topic, but I find them all to intricate to understand how such a simple example should be drafted ,esp how to pass the arguments from the original function.
All help and pointers appreciated
That's because you're not forwarding the args from the function to your decorator, and the catch-all exception catches the NameError for args; one of the reasons to always specify the exception class.
Here's a modified version of your code with the try-catch removed and the function arguments correctly forwarded:
def log(fun):
def wrapper(*args):
print('in decorator!')
return fun(*args)
return wrapper
#log
def sum_(a,b):
return a+b
print sum_(1,2)
The reason you're getting an error is simply because args is undefined in your decorator. This isn't anything special about decorators, just a regular NameError. For this reason you probably want to restrict your exception clause to just TypeErrors so that you're not silencing other errors. A full implementation would be
import functools
def log(fun):
#functools.wraps(fun)
def inner(*args):
try:
return fun(*args)
except TypeError:
print('error!')
return inner
#log
def sum_(a, b):
return a + b
It's also a good idea to decorate your inner functions with the functools.wrap decorator, which transfers the name and docstring from your original function to your decorated one.
The log decorator, in this case, does not return a function, but a value. This may point on an assumption that the decorator function replaces the original function, where in fact, it is called to create a replacement function.
A fix which may represent the intention:
def log(fun):
def my_func(*args):
try:
return fun(*args)
except:
print('error!')
return my_func
In this case, my_func is the actual function which is called for sum_(1, 2), and internally, it calls the original function (the original sum_) which the decorator received as an argument.
A trivial example that illustrates the order of the actions:
def my_decorator(fun):
print 'This will be printed first, during module load'
def my_wrapper(*args):
print 'This will be printed during call, before the original func'
return fun(*args)
return my_wrapper()
#my_decorator
def func():
print('This will be printed in the original func')

Python decorator function execution

I have below decorator demonstration code. If I execute it without explicitly calling greet function, it is executing print statement inside decorator function and outputs Inside decorator.
I am unable to understand this behavior of decorator. How the time_decorator is called even if I didn't call greet function?
I am using Python 3.
def time_decorator(original_func):
print('Inside decorator')
def wrapper(*args, **kwargs):
start = time.clock()
result = original_func(*args, **kwargs)
end = time.clock()
print('{0} is executed in {1}'.format(original_func.__name__, end-start))
return result
return wrapper
#time_decorator
def greet(name):
return 'Hello {0}'.format(name)
Decorators are called at start time (when the python interpreter reads the code as the program starts), not at runtime (when the decorated function is actually called).
At runtime, it is the wrapped function wrapper which is called and which itself calls the decorated function and returns its result.
So this is totally normal that the print line gets executed.
If, i.e, you decorate 10 functions, you will see 10 times the print output. No need to even call the decorated functions for this to happen.
Move the print inside wrapper and this won't happen anymore.
Decorators as well as metaclasses are part of what is called meta-programming (modify / create code, from existing code). This is a really fascinating aspect of programming which takes time to understand but offers amazing possibilities.
time_decorator is executed during function decoration. wrapper is not (this is function invoked when decorated greet() is called).
# is just syntactic sugar. Following code snippets are equivalent.
Decorator syntax:
#time_decorator
def greet(name):
return 'Hello {0}'.format(name)
Explicit decoration process - decorator is a function that returns new function based on another one.
def greet(name):
return 'Hello {0}'.format(name)
greet = time_decorator(greet)

Is #measured a standard decorator? What library is it in?

In this blog article they use the construct:
#measured
def some_func():
#...
# Presumably outputs something like "some_func() is finished in 121.333 s" somewhere
This #measured directive doesn't seem to work with raw python. What is it?
UPDATE: I see from Triptych that #something is valid, but is where can I find #measured, is it in a library somewhere, or is the author of this blog using something from his own private code base?
#measured decorates the some_func() function, using a function or class named measured. The # is the decorator syntax, measured is the decorator function name.
Decorators can be a bit hard to understand, but they are basically used to either wrap code around a function, or inject code into one.
For example the measured function (used as a decorator) is probably implemented like this...
import time
def measured(orig_function):
# When you decorate a function, the decorator func is called
# with the original function as the first argument.
# You return a new, modified function. This returned function
# is what the to-be-decorated function becomes.
print "INFO: This from the decorator function"
print "INFO: I am about to decorate %s" % (orig_function)
# This is what some_func will become:
def newfunc(*args, **kwargs):
print "INFO: This is the decorated function being called"
start = time.time()
# Execute the old function, passing arguments
orig_func_return = orig_function(*args, **kwargs)
end = time.time()
print "Function took %s seconds to execute" % (end - start)
return orig_func_return # return the output of the original function
# Return the modified function, which..
return newfunc
#measured
def some_func(arg1):
print "This is my original function! Argument was %s" % arg1
# We call the now decorated function..
some_func(123)
#.. and we should get (minus the INFO messages):
This is my original function! Argument was 123
# Function took 7.86781311035e-06 to execute
The decorator syntax is just a shorter and neater way of doing the following:
def some_func():
print "This is my original function!"
some_func = measured(some_func)
There are some decorators included with Python, for example staticmethod - but measured is not one of them:
>>> type(measured)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'measured' is not defined
Check the projects import statements to see where the function or class is coming from. If it uses from blah import * you'll need to check all of those files (which is why import * is discouraged), or you could just do something like grep -R def measured *
Yes it's real. It's a function decorator.
Function decorators in Python are functions that take a function as it's single argument, and return a new function in it's place.
#classmethod and #staticmethod are two built in function decorators.
Read more ยป
measured is the name of a function that must be defined before that code will work.
In general any function used as a decorator must accept a function and return a function. The function will be replaced with the result of passing it to the decorator - measured() in this case.

Categories