I read "Fluent Python" again today, and I have a better understanding of Python's global, nonlocal keywords, closures and decorators.
For global variables defined in python, as opposed to local variables (generally defined in functions), one of the main differences between global variables and local variables is:
Inside a function, global variables can only be accessed, but not directly manipulated. If you want global variables to change closely with the operation of the function, you need to use global variables inside the functionKeywords, see example below
Example 1: The global variable is not directly manipulated, and the value of the global variable does not change
outer = 'Global variable'def f1():a = outer + 'ok'print(a)f1()print(outer)
Output:
Global variable okGlobal variables
Example 2: Operate global variables directly inside the function, resulting in an error
outer = 'Global variable'def f2():outer = outer + 'ok'print(outer)f2()print(outer)
Output:
UnboundLocalError: local variable 'outer' referenced before assignment
Example 3: The global variable can be directly manipulated inside the function, and the global variable can be changed immediately after the function call (here I call it twice to make the result obvious)
def f3():global outerouter = outer + 'ok'print(outer)f3()print(outer)f3()print(outer)
Output:
Global variable okglobal variable okglobal variable okokGlobal variable okok
If I define a function and define another function inside the function, like the following,
def outer():outerNum = 10def inner():pass
If I want to call the outerNum of the external function in the internal function, and let the external outerNum change with the change of the internal function call, then the nonlocal keyword is required, Let's see a few more and the above globalSimilar examples are easy to understand
Example 1: I did not use nonlocal here, so outerNum does not change with internal calls
def outer():outerNum = 10def inner():innerNum = outerNum + 10print(innerNum)inner()print(outerNum)outer()
Output:
2010
Example 2: Because the nonlocal keyword is not used here, the inner function operates on outerNum, resulting in an error
def outer():outerNum = 10def inner():outerNum = outerNum + 10print(outerNum)inner()print(outerNum)outer()
Output:
UnboundLocalError: local variable 'outerNum' referenced before assignment
Example 3: The external function variable is called using nonlocal in the internal function, and the external function variable is changed by the internal function call (here called several times for more obvious)
def outer():outerNum = 10def inner():nonlocal outerNumouterNum = outerNum + 10print(outerNum)inner()print(outerNum)inner()print(outerNum)inner()print(outerNum)outer()
Output:
202030304040
A closure, to put it bluntly, looks like a nested function, but the outer function can only call the inner function, and the inner function can call the variables of the outer function (at this time, the above nonlocal keyword plays a rolefunction), I once saw a Dart language lecturer mention - the advantages of closures:
1. Permanent memory 2. Does not pollute the whole world
Look at the following example - a function that finds the population mean based on continuously adding values:
def averageNUM():nums = []def inner(anum):nums.append(anum)return sum(nums) / len(nums)return innerarg = averageNUM()print(arg(1))print(arg(2))print(arg(3))
Results:
1.01.52.0
It can be seen from the example - since the value becomes resident memory, it will not be released after the function ends (but it takes up memory).
This way of defining a closure looks a lot like an anonymous function, but the anonymous function frees the memory after each use (and throws it away).
Before introducing the decorator, let's look at two functions with the same function - both functions to find the square root of the number 4:
def useFunc(func):return func(4)def getSqrt(n):return n**.5print(useFunc(getSqrt))# 2.0
def useFunc(func):return func(4)@useFuncdef getSqrt(n):return n**.5print(getSqrt)# 2.0
Scheme 2 is a simple decorator - according to scheme 1, you can roughly understand that when the parameter of a function is a function, you can choose a decorator. If it is only a function as a parameter, a main function cannot see anything;If you drop the same decorator for multiple functions, you can reflect the magical function of the decorator - Extend additional functions, unified and easy to manage.
def useFunc(func):print('Extra function')return func(4)@useFuncdef getSqrt(n):return n**[email protected] anotherFunc1(n):return n**[email protected] anotherFunc2(n):return n * 2print(getSqrt)print(anotherFunc1)print(anotherFunc2)
Output:
Extra featuresExtra featuresExtra features2.0168
OK, that's almost what I got today, bye...