I'm trying to understand the following example I found explaining decorators
:
#!/usr/bin/python
def get_text(name):
return "lorem ipsum, {0} dolor sit amet".format(name)
def p_decorate(func):
def func_wrapper(name):
return "<p>{0}</p>".format(func(name))
#return "1"
return func_wrapper
get_text = p_decorate(get_text)
print get_text("John")
The output of this is:
<p>lorem ipsum, John dolor sit amet</p>
I decided to try and change this function up and commented out return func_wrapper
and replaced it with return "1"
.
When I do this, I get the error:
TypeError: 'str' object is not callable
I have 2 questions regarding this:
When the line
print get_text("John")
is executed, is
def func_wrapper(name):
initialised with "John"
? What is the sequence of events after this line is run?
Why am I getting this error, because in the end, isn't a string
ultimately being returned anyway?
If anyone could explain the flow of events with this code, I would greatly appreciate it.
You called the decorator here:
get_text = p_decorate(get_text)
Normally, a decorator replaces a function with another callable (another function, for example), or returns the original function but having registered information about it.
But by changing the return value of p_decorate()
to "1"
rather than the function wrapper, you 'broke' get_text
as that is no longer a function now. You cannot call a string object like you could call a string.
Before, p_decorate()
returned the func_wrapper()
function object, so get_text
was rebound to point to that function. Calling get_text('John')
really called that nested function. func_wrapper()
is then indeed called with 'John'
as the argument, yes. Functions are after all just objects, you can assign those objects to any valid Python name you like.
When func_wrapper()
is called, it in turn calls func()
, which was the argument to p_decorate()
. Again, functions are just objects, so having called p_decorate(get_text)
, func
ends up still bound to the original get_text
function object. Calling func()
calls that original function.
You can see the full flow of the calls in Python Tutor.