Functions as objects and closures
The functions in Python are that first-class objects they can be passed as parameters to other functions, can be stored in data structures, or can be used as return values for functions
A simple example
# Foo.pydef CALLF (func): return func ()
>>> import foo>>> def hello (): ... Return ' Hello ' ... >>> f = foo.callf (Hello) # function as an arg>>> f ' hello '
Make a little change to the above code:
# Foo.pyx = 42def Callf (func): return func ()
>>> import foo>>> x = 37>>> def hello (): ... Return ' Hello. X is%d '% x...>>> foo.callf (hello) ' Hello. X is 37 '
Here we call FOO.CALLF (), but the value of x is not the value of the variable defined in foo.py, but the value before the function is called. Therefore, we should pay attention to the relationship between a function and the surrounding variables, there is the concept of closure closure
closure: When a function's statement is packaged with the environment they are executing, it becomes the so-called closure we can look at the properties of a function __globals__ , such as:
>>> hello.__globals__{' __builtins__ ': <module ' __builtin__ ' (built-in);, ' HelloWorld ': <function HelloWorld at 0x7bb30>, ' x ': Notoginseng, ' __name__ ': ' __main__ ', ' __doc__ ': None ' foo ': <module ' foo ' from ' foo.py ';}
You can see that Hello is already bound to x=37.
When using nested functions, closures give you inner function the environment to capture the execution needs, such as
Import Foodef Bar (): x = def helloworld (): return "Hello world." X is%d "% x foo.callf (HelloWorld) # returns ' Hello world, X is 13 '
Here the intrinsic function HelloWorld and x=13 have formed a closure
How can closures be used? Let's look at an example of a delay assignment:
From Urllib import urlopendef page (URL): def get (): return Urlopen (URL). Read () return get
>>> python = page ("http://www.python.org") >>> python<function get at 0x95d5f0>>>> Pydata = Python () # fetch http://www.python.org>>> pydata.__closure__ (<cell at 0x67f50:str object at 0x69230& gt;,) >>> python._ _closure_ _[0].cell_contents ' http://www.python.org '
The Pydata object is bound to the value of the parameter URL when it is assigned, and can be reserved for later invocation
Decorators
The function of the decorator decorator is to encapsulate other functions or classes inside, denoted by the @, eg:
@tracedef Square (x): return x*x
Equivalent to
def Square (x): return x*xsquare = Trace (square)
This example defines a square () function, but immediately passes it as a parameter to the trace () and replaces the returned object with the original square. Adorners as the name implies is to add some decorations to the original function, for example, we here the trace function can do some extra things, the last object returned can be a function containing square, that is, our square function "decorate"
Let's look at an example of the usual use:
enable_tracing = Trueif enable_tracing: debug_log = open ("Debug.log", "W") def Trace (func): if enable_tracing: def CALLF (*args,**kwargs): debug_log.write ("Calling%s:%s,%s\n"% (func._ _name_ _, args, Kwargs)) r = Func (*args,**kwargs) Debug_log.write ("%s returned%s\n"% (func._ _name, R)) return R return CALLF else: return func
This code can trace the call of the square function above, if enable_tracing, then use the function CALLF to encapsulate the Func, add the logging function inside, and CALLF finally return the Func function, That is, if we allow tracing, we will decorate the original function object as a tracking function object return, if not allow tracing, simply return to the Func itself, this is a very subtle design of the CALLF
Python Closures and decorators