一 闭包
什么是闭包
封装了数据和函数的函数,其实就是两个函数的嵌套
闭包有什么作用
具有数据和功能,内存开销比对象小,做装饰器
只发生在函数的嵌套中,一个内层函数调用了外层函数的"变量"
nonlocal 不是本地作用域的
检测是否为闭包的内置属性 __closure__
闭包函数可以保留其用到的变量的引用
外层函数的返回值就是内层函数的引用
闭包和函数的区别:
闭包:在闭包中,既有函数,又有数据,而且数据是闭包里面独有的数据,与外界无影响;
函数:函数中,需要使用的全局变量,在一定程度上是受到限制的,因为全局变量不仅仅是一个函数使用,其他的函数也可能会使用到,
一旦修改会影响到其他函数使用全局变量,所以全局变量不能随便修改从而在函数的使用中受到一定局限性。
代码如下:
def text(k,b):
def text1(x):
print(k*x + b)
return text1
t = text(1,2)
t(2)
一 装饰器是什么
python的装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。简单的说装饰器就是一个用来返回函数的函数。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
1 模板装饰器
def wrapper(func):
def inner(*args, **kwargs):
result = func(*args, **kwargs)
return result
return inner
@wrapper # text=wrapper(text)
def text():
print("python")
2 多个装饰器装饰同一个函数
def wrapper(func):
def inner(*args, **kwargs):
ret = func(*args, **kwargs)
return "<p>" + ret + "</p>"
return inner
def decorate(func):
def inner(*args, **kwargs):
ret = func(*args, **kwargs)
return "<h1>" + ret + "</h1>"
return inner
@wrapper
@decorate
def show():
return " ++love python++ "
ret = show()
print(ret)
result : "<p><h1> ++love python++ </h1></p>"
3 装饰器带参数
def set_lever(lever_num):
def wrapper(func):
def inner(*args, **kwargs):
if lever_num == 1:
print("已经获得1的权限")
elif lever_num == 2:
print("已经获得2的权限")
ret = func(*args, **kwargs)
return ret
return inner
return wrapper
@set_lever("first")
def text1():
# print("ha111")
return "love python111"
@set_lever("second")
def text2():
print("ha222")
return "love python222"
print(text1)
4 functools.wraps
使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、__name__、参数列表,先看例子:
def use_logging(func):
def _deco(*args,**kwargs):
print("%s is running" % func.__name__)
func(*args,**kwargs)
return _deco
@use_logging
def bar():
print('i am bar')
print(bar.__name__)
bar()
#bar is running
#i am bar
#_deco
#函数名变为_deco而不是bar,这个情况在使用反射的特性的时候就会造成问题。因此引入了functools.wraps解决这个问题。
import functools
def use_logging(func):
@functools.wraps(func)
def _deco(*args,**kwargs):
print("%s is running" % func.__name__)
return func(*args,**kwargs)
return _deco
@use_logging
def bar():
print('i am bar')
print(bar.__name__)
bar()
#result:
#bar is running
#i am bar
#bar ,这个结果是我们想要的。OK啦!
5 带参数和不带参数的装饰器
import functools
def use_logging(arg):
if callable(arg):#判断参入的参数是否是函数,不带参数的装饰器调用这个分支
@functools.wraps(arg)
def _deco(*args,**kwargs):
print("%s is running" % arg.__name__)
return arg(*args,**kwargs)
return _deco
else:#带参数的装饰器调用这个分支
def _deco(func):
@functools.wraps(func)
def __deco(*args, **kwargs):
if arg == "warn":
print "warn%s is running" % func.__name__
return func(*args, **kwargs)
return __deco
return _deco
@use_logging("warn")
# @use_logging
def bar():
print('i am bar')
print(bar.__name__)
bar()
三 类装饰器
1 普通类装饰器
class loging(object):
def __init__(self,level="warn"):
self.level = level
def __call__(self,func):
@functools.wraps(func)
def _deco(*args, **kwargs):
if self.level == "warn":
self.notify(func)
return func(*args, **kwargs)
return _deco
def notify(self,func):
# logit只打日志,不做别的
print "%s is running" % func.__name__
@loging(level="warn")#执行__call__方法
def bar(a,b):
print('i am bar:%s'%(a+b))
bar(1,3)
2 继承类装饰器
class email_loging(Loging):
'''
一个loging的实现版本,可以在函数调用时发送email给管理员
'''
def __init__(self, email='admin@myproject.com', *args, **kwargs):
self.email = email
super(email_loging, self).__init__(*args, **kwargs)
def notify(self,func):
# 发送一封email到self.email
print "%s is running" % func.__name__
print "sending email to %s" %self.email
@email_loging(level="warn")
def bar(a,b):
print('i am bar:%s'%(a+b))
bar(1,3)