Python3 "Basics"-decorators

Source: Internet
Author: User
Tags closure wrapper

To understand the full understanding of Python's adorners, there are three knowledge points that are fully understood as prerequisites:

    • Python scope rules
    • function is Object
    • Closed Package

One, Python scope rules:

The scope rules in Python are introduced first. Python's scope rules follow the LEGB rule, what do these four letters mean? The following describes each:

    • l:local function Internal Scope
    • e:enclosing function inside and inline function
    • G:global Global scope
    • B:build-in built-in scopes

The priority of the four scopes above is l>e>g>b, what does it mean in the code? Let's say for example.

1. Local internal scopes

With the following code, there is a num variable inside and outside the Foo () function, and the NUM variable is called inside the function, and Python first calls the internal Num. Num within the function is only valid within the function, i.e. its lifetime is invalidated by the internal NUM variable after the function call ends.

num = 90deffoo (): Num= 100Print("the address of the function internal variable num is: {_id}". Format (_id=ID (num))) Print("Internal Num:{_num}". Format (_num=num)) Foo ()Print("the address of the function external variable num is: {_id}". Format (_id=ID (num)))Print("External Num:{_num}". Format (_num=num))

# Execute the above code to get the following result:

# The address of the function internal variable num is: 4305316064
# internal NUM:100
# The address of the function external variable num is: 4305315744
# external Num:90

2. Between the enclosing function interior and the inline function

Python's functions support nested definitions, where functions are defined inside a function, and functions are treated as an object and returned. In this way, you can use a variable to receive an internal function when calling an external function.

We defined the FOO2 function inside the foo1 and returned the Foo2. The so-called enclosing refers to the scope between Foo2 and foo1.

Code Snippet 1:

deffoo1 (): Num= 100deffoo2 (): Num= 90Print("foo2-num_id:{_id}". Format (_id=ID (num))) Print("Foo2-num:{_num}". Format (_num=num)) Print("foo1-num_id:{_id}". Format (_id=ID (num))) Print("Foo1-num:{_num}". Format (_num=num)) returnFoo2
Foo2 = Foo1 ()
Foo2 ()

# Execute the above code to:

# foo1-num_id:4305316064
# foo1-num:100
# foo2-num_id:4305315744
# foo2-num:90

Code Snippet 2:

deffoo1 (): Num= 100defFoo2 ():#num =        Print("foo2-num_id:{_id}". Format (_id=ID (num))) Print("Foo2-num:{_num}". Format (_num=num)) Print("foo1-num_id:{_id}". Format (_id=ID (num))) Print("Foo1-num:{_num}". Format (_num=num)) returnFoo2foo2=foo1 () Foo2 ()

# Execute the above code to:

# foo1-num_id:4305316064
# foo1-num:100
# foo2-num_id:4305316064
# foo2-num:100

In contrast to code snippet 1 and Code snippet 2, it can be seen that within FOO2, when the NUM variable is called, the internal NUM variable is called first, and if the internal variable num does not exist, the outer layer is searched for Num.

3. Global scope

The global scope refers to the entire Python file. 1 num = 1 2 3 def foo1 ():

4num = 25 6     defFoo2 ():7num = 38         Print(num)9 Ten     Print(num) One  A     returnFoo2 -  - Print(num) theFoo2 =foo1 () -Foo2 ()

# Execute the above code to:
1
2
3

The code above has three num variables, where num in line 1th belongs to the full scope.

4. Build-in built-in scopes

def Max (A, b    ): return Max (A, b) Print (Max)

In the code above, when the compiler compiles the Max function, it discovers that the Max function contains the Max function, and that neither the local scope nor the global scope has the Max function, and the compiler goes to the built-in scope to find Max.

Second, the function is the object:

In the world of Python, functions are the same as our previous [All-in-one], ' ABC ', 8 and so on, and the function is the most advanced object (the object is an instantiation of the class, the corresponding method can be called, and the function contains the object of the variable object).

  

Let's take a look at the Python variables in memory.

We define a a=8, in fact a store is not the value of ' 8 ', but the ' 8 ' address in memory. When this operation is b=a, the memory address containing ' 8 ' in A is assigned to B, so that b also points to 8. At this point, A and B show the same value. In the same way, we define a function foo (), which executes print (' OK '), at which point when the compiler compiles the function foo (), the function name of Foo is pointed to the address in memory of the statement "print (' OK '). In Python, a function is an object, and since it is an object, we can change it (assign a value), and executing bar=foo means that the bar variable points to the address of print (' OK ') in memory.

Based on the above understanding, we can draw the following two conclusions:

  1. Function names can be assigned to other variables

def foo ():     Print ('I am foo ... '  = foobar ()#  Execute the above code, print ' I am foo ... '

  2. Function names can be passed as parameters of a function, type strings, lists, etc.

def foo ():     Print ('I am foo ... ' )def  func (f):    F ()    func (foo)#  executes the above code and prints ' I am foo ... '

3. Function names can be returned as return values

def foo1 ():     def Foo2 ():         Print ('I am foo2')     return  = foo1 () foo ()

# Execute the above code, print ' I am foo2 ... '

Three, closed package

  First, consider a closure instance.

def outer (num):     def inner ():         Print (num)     return  = outer () func ()

The above code is an instance of a closure. Let's examine the code:

1. The scope of the parameter (variable) num is the entire outer function, which is also valid in the inner function.

2. Inner function (according to the previous content, we can interpret it as a variable) whose scope is also valid within the function outer.

However, we call the outer function in the code, at which point it returns the inner function being received by Func. We execute the Func function again, and it successfully prints the value of num, and there is a doubt that the NUM variable has run out of its scope, why is it still valid?

Originally, the above code constituted a closure function.

The so-called closure function is composed of two parts. One is an intrinsic function and the other is the environment in which the intrinsic function is defined, where Num is one of the environments where the inner function is defined at that time.

  Closures = function blocks + Environment when defining functions

  Return surface only returns the Innner function, but in fact it returns the environment in which the inner function was defined at that time (of course, the environment is not simply a num variable, there are many others ...).

Complete definition of closure: If a reference is made to a variable in an external scope (but not at the global scope) in an intrinsic function, then the intrinsic function is considered a closure (closure)

Four, decorative device 

  Having said so much, we can finally talk about decorators.

An adorner is essentially a function that handles other functions, allowing other functions to add additional functionality without the need to modify the code, and the return value of the adorner is also a function object. It is often used in scenarios where demand for slices is applied, such as inserting logs, performance testing, transaction processing, caching, and permission validation. Adorners are a great design for solving such problems, and with adorners, we can pull out a lot of similar code that is not related to the function itself and continue to reuse it. In summary, the function of an adorner is to add additional functionality to an already existing object .

Let's look at an example of an adorner:

Import TimedefShow_time (func):definner (): Start=time.time () func () End=time.time ()Print("spend%s"% (End-start)) returnInner@show_time#foo = show_time (foo)deffoo ():Print('foo ...') Time.sleep (2) @show_time#bar = show_time (bar)defBar ():Print('Bar ...') Time.sleep (2)

At this point there are two functions foo () and Bar (), and we want to look at the execution time of the two functions. At this point we define a show_time function whose argument is a function name and the return value is a function. Inside the function, execute the incoming function and print the time it was executed.

The function show_time is the adorner, which wraps the real business method func inside the function, and looks like Foo is decorated with the up and down time functions. In this example, when the function enters and exits, it is called a cross plane (Aspect), which is called tangent-oriented programming.

The @ symbol is the syntactic sugar of the adorner, which is used when defining the function and avoids the assignment of the value again.

Five, with parameters of the adorner

1. Adorner with variable length parameters

#*********************************** Variable length parameterImport TimedefShow_time (func):defWrapper (*args,**Kwargs): Start_time=time.time () func (*args,**Kwargs) End_time=time.time ()Print('spend%s'% (end_time-start_time)) returnWrapper@show_time#add=show_time (ADD)defAdd (*args,**Kwargs): Time.sleep (1) Sum=0 forIinchArgs:sum+=IPrint(sum) Add (2,4,8,9)

2. The adorner itself contains parameters

  

Import TimedefTime_logger (flag=0):defShow_time (func):defWrapper (*args, * *Kwargs): Start=time.time () func (*args, * *Kwargs) End=time.time ()Print('spend%s'% (Start-end)) ifflag:Print('Print Success')        returnwrapperreturnShow_time@time_logger (3)defAdd (*args, * *Kwargs): Time.sleep (1) Sum=0 forIinchArgs:sum+=IPrint(sum) Add (1, 2, 3, 4, 5)

@time_logger (3) did two things:

1. Time_logger (3) Gets the closure function show_time, which holds the environment variable flag

2. @show_time Add=show_time (ADD)

The Time_logger above is an adorner that allows parameters. It actually encapsulates a function of the original adorner and returns an adorner (a closure function that contains parameters). When we call @time_logger (3), Python can discover this layer of encapsulation and pass parameters to the adorner.

Python3 "Basics"-decorators

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.