简体   繁体   中英

Flow of python decorator functions

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:

  1. 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?

  2. 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 .

Just to complement.

You use nested functions when you want to pass args inside decorator:

def decorator(func):
    def wrapper(*args, **kwargs):
        print('My args:', *args, **kwargs)
        return func(*args, **kwargs)
    return wrapper

So you decorate:

def my_function(*args, **kwargs):
    pass
my_function = decorator(my_function)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM