闭包:在一个内部函数中对外部函数作用域(非全局作用域)的变量进行引用,那么内部函数就会被称为闭包。
闭包需要满足如下3个条件:
.存在于两个嵌套关系的函数中,并且闭包是内部函数;
.内部函数引用了外部函数的变量(自由变量);
.外部函数会把内部函数的函数名称返回。
# 闭包函数的实例:outer是外部函数 a和b都是外函数的临时变量
def outer( a ):
b = 10
def inner(): # inner是内函数
print(a+b) #在内函数中 用到了外函数的临时变量
return inner # 外函数的返回值是内函数的引用
if __name__ == '__main__':
demo = outer(5)
demo() # 15
demo2 = outer(7)
demo2() #17
'''
解析:
在这里我们调用外函数传入参数5
此时外函数两个临时变量 a是5 b是10 ,并创建了内函数,然后把内函数的引用返回存给了demo
外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
'''
装饰器本质上是一个python函数,可让其他函数不做任何代码变更前提下增加额外功能,装饰器的返回也是一个函数。
.装饰器是个嵌套函数
.内部函数是一个闭包。
.外部函数接收的是被修饰的函数(func)
def w1(func):
print(‘正在装饰’)
def inner():
print(‘正在验证权限’)
return inner()
@w1
def f1():
print(’f1')
切面需求场景:
插入日志
性能测试
事务处理
缓存
权限校验
...
多个装饰器:执行顺序:先执行@w2,后执行@w1
@w1
@w2
def f1():
print('---f1---')
带参数的装饰器:带参数的装饰器函数特点为返回结果是装饰器
def logging(level):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
print("[{level}]: enter function {func}()".format(level=level,func=func.__name__))
return func(*args, **kwargs)
return inner_wrapper
return wrapper
@logging(level='INFO')
def say(something):
print("say {}!".format(something))
# 如果没有使用@语法,等同于
# say = logging(level='INFO')(say)
@logging(level='DEBUG')
def do(something):
print("do {}...".format(something))
if __name__ == '__main__':
say('hello')
do("my work")
'''
结果:
[INFO]: enter function say()
say hello!
[DEBUG]: enter function do()
do my work...
解析:
当带参数的装饰器被打在某个函数上时,比如@logging(level='DEBUG'),它其实是一个函数,会马上被执行,只要这个它返回的结果是一个装饰器时,那就没问题。
'''
基于类实现的装饰器
class logging(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("[DEBUG]: enter function {func}()".format(func=self.func.__name__))
return self.func(*args, **kwargs)
@logging
def say(something):
print("say {}!".format(something))
'''
解析:
1、构造函数__init__里接受函数
2、重载__call__方法(返回函数)
'''
带参数的类装饰器
class logging(object):
def __init__(self, level='INFO'):
self.level = level
def __call__(self, func): # 接受函数
def wrapper(*args, **kwargs):
print("[{level}]:enter function {func}()".format(level=self.level, func=func.__name__))
func(*args, **kwargs)
return wrapper # 返回函数
@logging(level='INFO')
def say(something):
print("say {}!".format(something))
'''
解析:
1、构造函数__init__里接受参数,非函数
2、重载__call__方法(接受函数并返回函数)
'''
内置装饰器
特性装饰器:@property
类方法装饰器: @classmethod
静态方法装饰器:@staticmethod
特性装饰器:@property 可以把一个实例方法变成其同名属性,以支持实例访问,它返回的是一个property属性
import math
class Circle:
def __init__(self,radius): #圆的半径radius
self.radius=radius
@property
def area(self):
return math.pi * self.radius**2 #计算面积
@property
def perimeter(self):
return 2*math.pi*self.radius #计算周长
circle=Circle(10)
print(circle.radius)#常规方式访问类中属性
print(circle.area) #通过@property访问方法area/perimeter,会触发area函数的执行,返回面积值
print(circle.perimeter)
property对象还具有setter、deleter 可用作装饰器
setter: 设置属性值
deleter:删除属性值
getter: 获取属性值(实际使用可直接使用property获取)
class C:
def __init__(self):
self._x = None
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
c = C() # 实例化类
c.x = 100 # 为属性进行赋值
print(c.x) # 输出属性值,相当于使用getter方法
del c.x # 删除属性
类方法装饰器: @classmethod
@classmethod修饰的方法不需要实例化和self参数,但第一个参数为表示类自身的cls参数,可以用来调用类属性,类方法,实例化对象等
class A():
number = 10
@classmethod
def get_a(cls): #cls 接受类A,类A传入到被修饰的方法
print('这是类本身:',cls)# 如果子类调用,则传入的是子类
print('这是类属性:',cls.number)
class B(A):
number = 20
pass
A.get_a()# 调用类方法 不需要实例化可以直接调用类方法
B.get_a()
静态方法装饰器:@staticmethod
import time
class Date:
def __init__(self,year,month,day):
self.year=year
self.month=month
self.day=day
@staticmethod
def now(): #用Date.now()产生当前时间实例
t=time.localtime() #获取结构化的时间格式
return Date(t.tm_year,t.tm_mon,t.tm_mday) #新建实例并且返回
@staticmethod
def tomorrow():#用Date.tomorrow()的形式去产生实例,该实例用的是明天的时间
t=time.localtime(time.time()+86400)
return Date(t.tm_year,t.tm_mon,t.tm_mday)
a=Date('1987',11,27) #自己定义时间
print(a.year,a.month,a.day)
b=Date.now() #采用当前时间
print(b.year,b.month,b.day)
c=Date.tomorrow() #采用明天的时间
print(c.year,c.month,c.day)
'''
解析: @staticmethod改变一个方法为静态方法
1、静态方法把某个普通函数归属于类对象 Date.now()和Date.tomorrow()为当前和明天时间实例
2、静态方法本质为普通函数,因此,第一个形参没有特殊含义和要求。
2、静态方法可以被类对象所调用,语法格式为:类对象.方法名([实参])或cls.方法名([实参])
'''