1, Closure
1. Definition
A closure is a function that extends to a function that contains references in the body of the function definition, but non global variables that are not defined in the body of the definition. It doesn't matter whether a function is anonymous or not. The key is that it can access non global variables defined outside the definition body.
A closure is a function that preserves the binding of free variables that exist when you define a function, so that when you call a function, you can still use those variables even though the definition scope is not available. (only functions nested in other functions may need to handle external variables that are not acting globally in.)
Human voice: closure is to get different results according to different configuration information (code example).
A closure is an entity composed of a function and its associated reference environment.
2. Code example
def fo_out(int_out): def fo_in(int_in): return int_in + int_out return fo_in a = fo_out(1) b = fo_out(1000) print a(1) print b(1000) //Output: 2 2000
3. Precautions
-
If the variable outside the definition body is of variable type (such as list), you can use append to pass the value.
def make_averager(): series=[] def averager(new_value): series.append() total=sum(series) return total/len(series) return averager
-
If the variables outside the definition body are immutable types (numbers, strings, tuples, etc.), you can declare nonlocal in the definition body to make it a free variable.
def make_averager(): count=0 total=0 def averager(new_value): nonlocal count,total count += 1 total += new_value return total/count return averager
OK, let's put the closure aside and look at the decorator again?
2, Decorator
1. Definition
A decorator is a callable object whose arguments are another function (the decorated function). The decorator may process the decorated function and return it, or replace it with another function or callable object.
Typical behavior: replace the decorated function with a new function, both of which take the same parameters, and (usually) return the value that the decorated function should have returned, while doing some additional operations.
2. Code example
@clock def factorial(n): return 1 if n<2 else n*factorial(n-1)
The above is equivalent to:
def factorial(n): return 1 if n<2 else n*factorial(n-1) factorial=clock(factorial)
It can be seen that the decorator is actually a simple way to write closures!
3. When does the decorator run?
registry = [] def register(func): print('running register(%s)' % func) registry.append(func) return func @register def f1(): print('running f1()') @register def f2(): print('running f2()') if __name__ == '__main__': print(u'Here we go') f1()
The operation result is:
running register(<function f1 at 0x000001F93DED7678>) running register(<function f2 at 0x000001F93DED7708>) //Here we go running f1()
Conclusion: even if the above code is import ed as a module in other py files, the decorator will run immediately! The decorated function, on the other hand, works normally only when it is explicitly called.
4. Decorators commonly used in the standard library
-
lru_cache (note function decorator)
definition
functools.lru_cache is a very practical decorator, which realizes the function of memo. This is an optimization technique, which saves the results of time-consuming functions and avoids repeated calculation when the same parameters are passed in.
example
import functools import time def clock(func): def clocked(*args): #Note: single *: import all parameters as tuples t0 = time.perf_counter() result = func(*args) elapsed = time.perf_counter() - t0 name = func.__name__ arg_str = ','.join(repr(arg) for arg in args) print('[%0.8fs]%s(%s) ->%r' % (elapsed, name, arg_str, result)) return result return clocked @functools.lru_cache() @clock # Other decorators def fibonacci(n): if n < 2: return n return fibonacci(n-2) + fibonacci(n-1) if __name__=='__main__': print(fibonacci(6))
-
Single dispatch
definition
@The single dispatch decorator can split the whole scheme into multiple modules, and even provide special functions for classes that you cannot modify. Ordinary functions decorated with @ singledispatch become pan functions: a set of functions that perform the same operation in different ways according to the type of the first parameter.
To be continued...