10.9 装饰器
在代码运行期间,在不改变原函数定义的基础上,动态给该函数增加功能的方式,称之为装饰器。
装饰器的作用就是为已经存在的对象添加额外的功能。
装饰器其实也是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值给原来的标识符,并永久丧失对原始函数对象的访问。
10.9.1 变量相关-作用域
outerVar="this is a global variable"
def test():
innerVar="this is a local variable"
print("local variable:")
print(locals()) #locals()返回test函数内部本地作用域的变量
print("global variable:")
print(globals())
test()
local variable:
{'innerVar': 'this is a local variable'}
global variable:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000216DA597588>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'd:\\2019\\py2.py', '__cached__': None, 'outerVar': 'this is a global variable', 'test': <function test at 0x00000216DA6380D8>}
10.9.2 变量相关-变量解析规则
如果在当前作用域中没有找到匹配的变量,会依次向上在闭合作用域中进行查找,所以在函数中直接访问全局变量也是可以的。
outerVar="this is a global variable"
def test():
innerVar="this is a local variable"
print(outerVar)
print(n)
n=10
test()
C:\Users\39621>python d:\2019\py2.py
this is a global variable
10
10.9.3 变量相关-变量生存空间
全局变量的生存周期是在整个程序执行期间有效,局部变量只在当前作用域中有效,一旦这个作用域不存在了,比如函数执行退出了,那么局部变量的生存周期就结束了。
outerVar="this is a global variable"
def test():
innerVar="this is a local variable"
print(innerVar)
test()
print(innerVar)
this is a local variable
Traceback (most recent call last):
File "d:\2019\py2.py", line 9, in <module>
print(innerVar)
NameError: name 'innerVar' is not defined
10.9.4 变量相关-嵌套函数
函数就是对象,可以把函数像参数一样传递给其他函数或者从函数中返回函数。
def outer():
name="outerVar"
def inner():
print(name)
return inner()
outer()
C:\Users\39621>python d:\2019\py2.py
outerVar
10.9.5 变量相关-函数作为变量
def add(x,y):
return x+y
def sub(x,y):
return x-y
def apply(func,x,y):
return func(x,y)
print(apply(add,1,2))
print(apply(sub,3,1))
C:\Users\39621>python d:\2019\py2.py
3
2
10.9.6 闭包
def outer():
name="python"
def inner():
print(name)
return inner
outer()
outer()() #-->inner()
print(outer().__closure__)
Ø 如果一个函数定义在另一个函数的作用域内,并引用了外层函数的变量,则该函数称为闭包。外层函数中被引用的变量叫做该函数的环境变量。环境变量和这个函数一起构成了闭包。
Ø 左例中,inner()就是一个闭包,本身是一个函数,并访问name。
Ø outer().__closure__查看闭包变量
Ø 每次outer(),inner函数都会被重新定义,每次的name都一样。修改一下则会不一样,见下例:
def outer(name):
def inner():
print(name)
return inner
res1=outer("python")
res2=outer("java")
res1()
print(res1.__closure__)
res2()
print(res2.__closure__)
C:\Users\39621>python d:\2019\py2.py
python
(<cell at 0x000001AEFA706048: str object at 0x000001AEFA71AC70>,)
java
(<cell at 0x000001AEFA7060D8: str object at 0x000001AEF8B152F0>,)
10.9.7 装饰器
装饰器其实就是一个闭包,把一个函数当作参数后返回一个替代版函数。
def log(func):
def wrapper():
print(func.__name__)
return func()
return wrapper
@log
def now():
print(time.strftime("%H:%M:%S",time.localtime()))
def myfunc():
print("calling myfunc()")
def deco(func):
print("before calling myfunc()")
func()
print("after calling myfunc()")
return func
deco(myfunc)
C:\Users\39621>python d:\2019\py2.py
before calling myfunc()
calling myfunc()
after calling myfunc()
def myfunc():
print("calling myfunc()")
def deco(func):
print("before calling myfunc()")
func()
print("after calling myfunc()")
return func
f=deco(myfunc)
f()
f()
before calling myfunc()
calling myfunc()
after calling myfunc()
calling myfunc()
calling myfunc()
def deco(func):
print("before calling myfunc()")
func()
print("after calling myfunc()")
return func
@deco
def myfunc():
print("calling myfunc()")
before calling myfunc()
calling myfunc()
after calling myfunc()
def deco(func):
print("before calling myfunc()")
func()
print("after calling myfunc()")
return func
@deco
def myfunc():
print("calling myfunc()")
myfunc()
myfunc()
before calling myfunc()
calling myfunc()
after calling myfunc()
calling myfunc()
calling myfunc()
def deco(func):
def _deco():
print("before calling myfunc()")
func()
print("after calling myfunc()")
return _deco
@deco
def myfunc():
print("calling myfunc()")
myfunc()
myfunc()
before calling myfunc()
calling myfunc()
after calling myfunc()
before calling myfunc()
calling myfunc()
after calling myfunc()
def deco(func):
def _deco(a,b):
print("before calling myfunc()")
res=func(a,b)
print("after calling myfunc()")
print("res:",res)
return res
return _deco
@deco
def myfunc(a,b):
print("calling myfunc()")
print("a+b=",a+b)
return a+b
myfunc(1,2)
myfunc(3,4)
before calling myfunc()
calling myfunc()
a+b= 3
after calling myfunc()
res: 3
before calling myfunc()
calling myfunc()
a+b= 7
after calling myfunc()
res: 7
def deco(func):
def _deco(*args,**kwargs):
print("before calling %s" %func.__name__)
res=func(*args,**kwargs)
print("after calling %s" %func.__name__)
print("res:",res)
return res
return _deco
@deco
def myfunc1(a,b):
print("calling myfunc()1")
print("a+b=",a+b)
return a+b
@deco
def myfunc2(a,b,c):
print("calling myfunc()2")
print("a+b+c=",a+b+c)
return a+b+c
@deco
def myfunc3(a,b):
print("calling myfunc()3")
print("a+b=",a+b)
return a+b
myfunc1(1,2)
myfunc2(1,2,3)
myfunc3(a=3,b=4)
before calling myfunc1
calling myfunc1()
a+b= 3
after calling myfunc1
res: 3
before calling myfunc2
calling myfunc2()
a+b+c= 6
after calling myfunc2
res: 6
before calling myfunc3
calling myfunc3()
a+b= 7
after calling myfunc3
res: 7
def deco(arg):
def _deco(func):
def __deco():
print("before calling %s,[%s]" %(func.__name__,arg))
func()
print("after calling %s,[%s]" %(func.__name__,arg))
return __deco
return _deco
@deco("mymodule")
def myfunc1():
print("calling myfunc1()")
@deco("module2")
def myfunc2():
print("calling myfunc2()")
myfunc1()
myfunc2()
before calling myfunc1,[mymodule]
calling myfunc1()
after calling myfunc1,[mymodule]
before calling myfunc2,[module2]
calling myfunc2()
after calling myfunc2,[module2]
def deco(arg):
def _deco(func):
def __deco(*args,**kwargs):
print("before calling %s,[%s]" %(func.__name__,arg))
res=func(*args,**kwargs)
print("res=",res)
print("after calling %s,[%s]" %(func.__name__,arg))
return __deco
return _deco
@deco("mymodule")
def myfunc1(a,b):
print("calling myfunc1()")
print("a+b=",a+b)
return a+b
@deco("module2")
def myfunc2(a,b):
print("calling myfunc2()")
print("a+b=",a+b)
return a+b
myfunc1(1,2)
myfunc2(a=3,b=4)
before calling myfunc1,[mymodule]
calling myfunc1()
a+b= 3
res= 3
after calling myfunc1,[mymodule]
before calling myfunc2,[module2]
calling myfunc2()
a+b= 7
res= 7
after calling myfunc2,[module2]
class locker:
def __init__(self):
print("locker.__init__() should be not called")
@staticmethod
def acquire():
print("locker.acquire() called")
@staticmethod
def release():
print("locker.release() called")
def deco(cls):
def _deco(func):
def __deco():
print(func.__name__,cls)
cls.acquire()
return func()
return __deco
return _deco
@deco(locker)
def myfunc():
print("myfunc() called")
myfunc()
myfunc()
myfunc <class '__main__.locker'>
locker.acquire() called
myfunc() called
myfunc <class '__main__.locker'>
locker.acquire() called
myfunc() called
class mylocker:
def __init__(self):
print("mylocker.__init__() called")
@staticmethod
def acquire():
print("mylocker.acquire() called")
@staticmethod
def unlock():
print("mylocker.unlock() called")
class lockerex(mylocker):
@staticmethod
def acquire():
print("lockerex.acquire() called")
@staticmethod
def unlock():
print("lockerex.unlock() called")
def deco(cls):
def _deco(func):
def __deco(*args,**kwargs):
print(func.__name__,cls)
cls.acquire()
try:
return func(*args,**kwargs)
finally:
cls.unlock()
return __deco
return _deco
#以下为另一个文件py3.py
from py2 import *
class example:
@lockhelper(mylocker)
def myfunc(self):
print("myfunc() called")
@lockhelper(mylocker)
@lockhelper(lockerex)
def myfunc2(self,a,b):
print("myfunc2() called")
return a+b
if __name__=="__main__":
a=example()
a.myfunc()
print(a.myfunc())
print(a.myfunc2(1,2))
C:\Users\39621>python d:\2019\py3.py
myfunc <class 'py2.mylocker'>
mylocker.acquire() called
myfunc() called
mylocker.unlock() called
myfunc <class 'py2.mylocker'>
mylocker.acquire() called
myfunc() called
mylocker.unlock() called
None
__deco <class 'py2.mylocker'>
mylocker.acquire() called
myfunc2 <class 'py2.lockerex'>
lockerex.acquire() called
myfunc2() called
lockerex.unlock() called
mylocker.unlock() called
3