Python Function decorator | Novice tutorial
python Closure in is formally defined as ( explain ) by :
If it's in an internal function , On the external scope ( But not in the global scope ) The variables are quoted , So internal functions are considered closures (closure).
python Function name in is a special variable , It can be used as the return value of another function , A closure is a function that returns another function , Its internal local variables are also referenced by another function .
The function of closures is to make a variable resident in memory .
def func(name): # Define outer functions
def inner_func(age): # Inner function
print('name: ', name, ', age: ', age)
return inner_func # Note here to return , To embody closures
if __name__ == '__main__':
bb = func('jayson') # Pass a string to func function , return inner_func And assign to variable
bb(28) # Call... Through variables func function , Pass in the parameter , To complete the closure
Print the results :
name: jayson , age: 28
Two uses :① You can read variables inside a function ,② Keep the values of these variables in memory at all times .
② Keep the local variables inside the function in memory all the time :
How to understand this sentence ? Generally speaking , The local variables inside the function after the function is run , Will be Python The garbage collection mechanism of is cleared from memory . If we want this local variable to be stored in memory for a long time , Then you can use closures to implement this function .
Borrow here
@ A thousand mountains of snow
Example ( From : A thousand mountains of snow : Explain profound theories in simple language python Closure ). Look at the code below .
Take an example similar to a board game to illustrate . Suppose the size of the chessboard is 50*50, The upper left corner is the origin of the coordinate system (0,0), I need a function , receive 2 Parameters , The directions are (direction), step (step), This function controls the movement of the chess pieces . Here's the thing to note , The starting point of each movement is the end point of the last movement .
def create(pos=[0,0]):
def go(direction, step):
new_x = pos[0]+direction[0]*step
new_y = pos[1]+direction[1]*step
pos[0] = new_x
pos[1] = new_y
return pos
return go
player = create()
print(player([1,0],10))
print(player([0,1],20))
print(player([-1,0],10))
In this code ,player It's actually a closure go An instance object of the function .
It ran three times , The first is along X The axis is moving forward 10 Came to [10,0], The second time is along Y The axis is moving forward 20 Came to [10, 20],, The third time is in the opposite direction X The shaft retreated 10 Came to [0, 20].
This proves , function create Local variable in pos Keep it in memory all the time , Not in create It is automatically cleared after calling .
Why is this so ? And the reason is that create yes go The parent function of , and go Is assigned a global variable , This leads to go Always in memory , and go Is dependent on create, therefore create It's always in memory , Not after the call , Garbage collection mechanism (garbage collection) Recycling .
This is the time , Closures make the internal variables of an instance object of a function , Become very much like the properties of an instance object of a class , Can always be saved in memory , And constantly calculate it .
The decorator is designed not to change the definition of the original function , And make the original function dynamically add functions at runtime , Generally speaking, decorators are higher-order functions that return functions .
In short : They are functions that modify the functions of other functions .
Decorators let you execute code before and after a function .
def hi(name="yasoob"):
def greet():
return "now you are in the greet() function"
def welcome():
return "now you are in the welcome() function"
if name == "yasoob":
return greet
else:
return welcome
a = hi()
print(a)
#outputs: <function greet at 0x7f2143c01500>
# It clearly shows `a` Now point to hi() Function greet() function
# Now try this
print(a())
#outputs: now you are in the greet() function
stay if/else In statement we return greet and welcome, instead of greet() and welcome().
When you put a pair of parentheses after a function , This function will execute ; However, if you don't put the parentheses after it , Then it can be passed around , And you can assign values to other variables without executing them .
Blueprint specification :
from functools import wraps
def decorator_name(f):
@wraps(f)
def decorated(*args, **kwargs):
if not can_run:
return "Function will not run"
return f(*args, **kwargs)
return decorated
@decorator_name
def func():
return("Function is running")
can_run = True
print(func())
# Output: Function is running
can_run = False
print(func())
# Output: Function will not run
1、 Functions to be decorated , As a variable , Passed into the decoration function
2、 Decoration function , There's only one reference , That's the decorated function
3、 Start execution of outermost layer return This function of , The variables inside are the decorated functions ( The function passed in )
In fact, this is the only piece of useful code , The rest of the mess should be ignored , The variable inside , Is the function passed in
A decorator can help to check if someone is authorized to use a web The endpoint of the application (endpoint). They are widely used in Flask and Django web In the frame . Here is an example of using decorator Based Authorization :
from functools import wraps
def requires_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
authenticate()
return f(*args, **kwargs)
return decorated
It's only a small piece that works
Log is another highlight of decorator application . This is an example :
from functools import wraps
def logit(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logit
def addition_func(x):
"""Do some math."""
return x + x
result = addition_func(4)
# Output: addition_func was called
It's only a small piece that works
Let's go back to the example of logs , And create a wrap function , Allows us to specify a log file for output .
from functools import wraps
def logit(logfile='out.log'):
def logging_decorator(func):
@wraps(func)
def wrapped_function(*args, **kwargs):
log_string = func.__name__ + " was called"
print(log_string)
# open logfile, And write content
with open(logfile, 'a') as opened_file:
# Now type the log to the specified logfile
opened_file.write(log_string + '\n')
return func(*args, **kwargs)
return wrapped_function
return logging_decorator
@logit()
def myfunc1():
pass
myfunc1()
# Output: myfunc1 was called
# Now one is called out.log Your file appears , The content is the string above
@logit(logfile='func2.log')
def myfunc2():
pass
myfunc2()
# Output: myfunc2 was called
# Now one is called func2.log Your file appears , The content is the string above
1、 Only this one is useful
2、 To wrap one more layer is to pass one more parameter