目录
1.闭包
1.1什么是闭包
在函数中可以(嵌套)定义另一个函数时,如果内部函数引用了外部函数的变量,则可能产生闭包。
闭包可以用来在一个函数与一组私有变量之间创建关联关系。
在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。
1.2形成闭包的三个条件
必须有一个内嵌函数
内部函数必须引用外部函数的变量
外部函数必须返回内函数
1.3一个简单的闭包函数
1.3.1创建
def outer():
tmp_list=[]
def inner(name):
tmp_list.append(1)
print(name,tmp_list)
return inner
# 外函数为outer,返回值是内部函数inner,inner为内函数,引用了外函数变量tmp_list
1.3.2调用闭包函数
#调用函数outer将返回值赋给d1,d1现在闭包函数中的inner,可以调用inner函数。
1.3.3再次调用闭包函数
#每次调用外函数,都会重新执行,创建一个新的tmp_list和inner
1.4__closure__属性
# 形成闭包之后,闭包函数会得到一个非空属性__closure__属性
1.5闭包原理深入
def outer():
fs = []
for i in range(5):
def inner():
return i * i
fs.append(inner)
return fs
f1, f2, f3, f4, f5 = outer()
# 执行完outer后, 将inner添加到了fs中
print(f1())
# 调用inner(),i=4,所以返回值是16
#不明白可以去debug调试中看下看执行过程。
1.6闭包的意义
# 闭包不是必须的 # 闭包只是提供了一种方案
2.装饰器
2.1什么是装饰器
装饰器时一种设计模式,在不改变原代码的基础上,添加额外功能。
本质上一种闭包函数
把函数当做参数传递的闭包就是装饰器
2.2装饰器初体验
import time
def runtime(func):
def inner():
start = time.time()
func()
end = time.time()
rt = end -start
return rt
return inner
@runtime #-->func1 = runtime(func1)
def func1():
time.sleep(1)
print(f"func1...")
@runtime
def func2():
time.sleep(2)
print(f"func2...")
inner1 = runtime(func1)
print(inner1())
inner2 = runtime(func2)
print(inner2())
输出如下
2.3装饰器进阶
一个函数可以同时用两个装饰器来装饰
user = {"root": "123456", "admin": "admin"}
name = input("请输入用户名:")
passwd = input("请输入密码:")
def login(func):
def inner1(*args, **kwargs):
if name in user.keys():
if user.get(name, 0) == passwd:
print(f"{name}登录成功")
result = func(*args, **kwargs)
return result
else:
print("密码错误")
else:
print("账户错误")
return inner1
def identify(func):
def inner2(*args, **kwargs):
if name == "root":
print("root权限")
print(func(*args, **kwargs))
else:
print("没有权限")
result = func(*args, **kwargs)
return result
return inner2
@login
@identify
def add(a, b):
return a+b
add(1, 2)
2.4保留原数据
add函数经装饰器装饰后返回的不是add,而是inner。
如果我们要获取add以及文档注释,该怎么做呢?
2.5装饰器传参
需要使用三层函数封装
#自身不需要传入参数,只需要两层函数封装
#自身需要传入参数,需要三层函数封装
如何实现两种功能继承于同一个装饰器呢?
import time
import functools
def deco(d = None, username = None):
def cost(func):
# 把func的元数据复制给inner
@functools.wraps(func)
def _cost(*args, **kwargs):
print(f"装饰器带参数:{username}")
start = time.time()
func()
end = time.time()
rt = end -start
return rt
return _cost
if d:
return cost(d)
else:
return cost
# @deco(username="sc")
# @deco()
@deco
def add():
print("this is add")
add()
带参数实现
不带参数实现
2.6属性包装装饰器
# @property 把方法当做属性来使用
# 设定Person属性age,可以修改age,当age范围不在0到100之间报错
class Person():
_age = 1
# age = 100
@property
#本身会创建另外两个装饰器 @age.setter @age.deleter
def age(self):
return self._age
@age.setter
def age(self, _age):
if 0< _age < 100:
self._age = _age
else:
raise ValueError("年龄不在范围内")
p = Person()
print(p.age)
p.age = 100
2.7用类实现装饰器
原理: 让类实现__call__函数,并返回一个函数
# 用类实现带参数的装饰器
# class A():
# def __init__(self, username):
# self.username = username
#
# def __call__(self, func):
# def deco(*args, **kwargs):
# func(*args, **kwargs)
# return deco
# @A("sc")
# def func1():
# print("I am func1")
#
# func1()
# 用类实现不带参数的装饰器
import time
class A():
def __init__(self,func):
self.func = func
def __call__(self, *args, **kwargs):
start = time.time()
result = self.func(*args, **kwargs)
end = time.time()
print(f"花费了{end-start}s")
return result
# 将func1作为参数传入类A,实例化出来一个对象func1
@A #func1 = A(func1)
def func1():
time.sleep(1)
#调用func1的__call__方法
func1()
2.8装饰类
def outer(cls):
def inner(*args, **kwargs):
print(f"class name is {cls.__name__}")
return cls(*args, **kwargs)
pass
return inner
# 将类A作为参数传入函数outer,返回inner
# 实例化m和m2,执行inner,返回一个实例化对象
@outer #--> A = outer(A)
class A:
def __init__(self, name):
self.name = name
print(type(A))
# 装饰器将A变为了一个函数inner
m = A("sc")
m2 = A("sc2")
print(m.name)
print(m2.name)