54
附加
生命周期
生命周期,每一个存储的数据都是有生命周期的
def outer():
a = 10
print(f"a is {a}")
#a的生命周期在outer中,出outer就到头了
outer()
print(a)
变量解析原则 --LEGB
- L – Local
- E – Enclosing function locals
- G – Global
- B – Builtin
闭包
什么是闭包
- 在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生 闭包。
- 闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。
- 在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。
闭包条件
- 必须要有一个内嵌函数
- 内函数必须引用外函数的变量
- 外函数必须返回内函数
#1.简单闭包
def outer(x):
a = 300
def inner():
print(f"两数之和为:{x+a}")
return inner
d = outer(10) #d是inner
d()
#形成闭包dir(d)就会有__closure__属性
#2。例子
def outer():
tmp_list = []
def inner(name):
tmp_list.append(1)
print(f"{name} -- {tmp_list}")
return inner
d1 = outer()
d2 = outer()
d1("d1")
d2("d2")
d1("d1")
print(id(d1),id(d2))
print(id(outer()),id(outer()))
输出:
d1 -- [1]
d2 -- [1]
d1 -- [1, 1]
1657755987984 1657758207280
1924411675632 1924411675632
#虽然代码一样,但每次调用外函数,都会重新执行,创建一个新的tmp_list和inner
#这里的outer()是一个匿名变量
闭包
- 形成闭包之后,闭包函数会获得一个非空的
__closure__
属性(对比我们最后的函数test,test是一 个不具备闭包的函数,它的__closure__
属性是None),这个属性是一个元组 - 元组里面的对象为cell对象,而访问cell对象的cell_contents属性则可以得到闭包变量的当前值 (即上一次调用之后的值)
- 而随着闭包的继续调用,变量会再次更新
- 所以可见,一旦形成闭包之后,python确实会将
__closure__
和闭包函数绑定作为储存闭包变量的 场所
装饰器
什么是装饰器
-
装饰器是这样一种设计模式:如果一个类(函数)希望添加其他类(函数)的一些功能,而不希望 通过继承或是直接修改源代码实现,那么可以使用装饰器模式
-
简单来说Python中的装饰器就是指某些函数或其他可调用对象,以函数或类作为可选输入参数, 然后返回函数或类的形式。通过这个在Python2.6版本中被新加入的特性可以用来实现装饰器设计 模式
-
装饰器就是一个可以接受调用也可以返回调用的函数,该函数接受被装饰的函数作为其位置参数。 装饰器通过使用该参数来执行某些操作,然后返回原始参数或一些其他的调用
-
函数也是对象,也可以当做参数传递
在这里插入代码片简而言之:装饰器就是在不改变函数或类的源代码的基础上,添加额外功能装饰器的本质就是闭包。它和闭包的不同是它需要传入一个callable对象
#统计运行时间的装饰器
import time
def runtime(func):
def inner():
start = time.time()
func()
end = time.time()
print(f"函数执行花了{end - start}s")
return inner
import time
@runtime #@修饰符去使用装饰器
def func1():
time.sleep(2)
print("func1....")
@runtime #func2 = runtime(func2)
def func2():
time.sleep(2)
print("func2....")
func1()
func2()
输出:
func1....
函数执行花了2.000455856323242s
func2....
函数执行花了2.0076518058776855s
改良版(可以传递0-~参数,返回返回值)
import time
def runtime(func):
print("this is runtime")
def inner(*args,**kwargs):
start = time.time()
result = func(*args,**kwargs)
end = time.time()
print(f"函数执行花了{end - start}s")
print(result)
return result
return inner
import time
@runtime #@修饰符去使用装饰器
def func1():
time.sleep(2)
print("func1....")
@runtime #func2 = runtime(func2)
def func2(a,b):
time.sleep(2)
print(f"func2....{a},{b}")
return a+b
func1()
print(func2(1,2))
输出:
this is runtime
this is runtime
func1....
函数执行花了2.002455711364746s
None
func2....1,2
函数执行花了2.009401559829712s
3
3
username = ''
def login_required(func):
def inner(*args,**kwargs):
if username == 'root':
print("欢迎")
result = func(*args,**kwargs)
return result
else:
return '没有权限'
return inner
#可以应用多个装饰器,但是要注意装饰器的执行顺序
#从最上面的装饰器的内函数开始执行
@runtime #add = runtime(login_required(add))
@login_required
def add(a,b):
return a+b
username = input("请输入你的username:")
print(add(1,2))
编写和使用装饰器
什么是元数据
元数据(Metadata),又称中介数据、中继数据,为描述数据的数据(data about data),主要是 描述数据属性(property)的信息(函数的重要的元信息比如名字、文档字符串、注解和参数签名等)
保留元数据
利用@functools.wraps(fun),将一个函数的重要内容复制到另一个函数
温馨提醒:任何时候你定义装饰器的时候,都应该使用 functools 库中的 @wraps 装饰器来注解底层 包装函数
内置的装饰器
Python还提供了类装饰器与@staticmethod,@classmethod,@property和这三个在面向对象编 程中常用的装饰器
- staticmethod:把类中定义的实例方法变成静态方法-
- classmethod:把类中定义的实例方法变成类方法
- property:把类中定义的实例方法变成类属性
import functools
import time
def runtime(func):
print("this is runtime")
#保留传递进来的函数的元数据,将他的元数据赋值给Inner
@functools.wraps(func)
def inner(*args,**kwargs):
start = time.time()
result = func(*args,**kwargs)
end = time.time()
print(f"函数执行花了{end - start}s")
print(result)
return result
return inner
username = ''
def login_required(func):
def inner(*args,**kwargs):
if username == 'root':
print(f"欢迎执行{func.__name__}函数")
result = func(*args,**kwargs)
return result
else:
return f'执行{func.__name__}权限不够'
return inner
#可以应用多个装饰器,但是要注意装饰器的执行顺序
#从最上面的装饰器的内函数开始执行
@login_required
@runtime #add = runtime(login_required(add))
def add(a,b):
return a+b
username = input("请输入你的username:")
print(add(1,2))
装饰器带参数
- 自身不传入参数的装饰器,使用两层函数定义
- 自身传入参数的装饰器,使用三层函数定义
def deco1(name):
def login_required(func):
def inner(*args,**kwargs):
if name == 'root':
print(f"欢迎执行{func.__name__}函数")
result = func(*args,**kwargs)
return result
else:
return f'执行{func.__name__}权限不够'
return inner
return login_required
#login_required = deco1(name = "root")
# add = login_required(add)
name = input("请输入你的name:")
@deco1(name)
def add(a,b):
return a+b
用类实现装饰器
#基于类实现装饰器
import time
class A:
def __init__(self,func):
self.func = func
def __call__(self, *args, **kwargs): #-->inner
start = time.time()
print("this is call")
result = self.func(*args, **kwargs)
time.sleep(1)
end = time.time()
print(end - start)
return result
@A
def func1(a,b):
print("i am func1...")
return a+b
print(func1(1,2))
#带参数的
import time
class A:
def __init__(self,name):
self.name = name
def __call__(self,func): #-->inner
def deco(*args,**kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"函数执行花了{end - start}")
return result
return deco
@A(name = input("请输入name:"))
#a1 = A("name")
#func1 = a1(func1)
def func1(a,b):
print("i am func1...")
return a+b
print(func1(1,2))
装饰类
def outer(cls):
def inner(*args,**kwargs):
print(f"class name is:{cls.__name__}")
return cls(*args,**kwargs)
return inner
@outer #A = outer(A)
class A:
def __init__(self,name):
self.name = name
print(type(A))
m = A("sc")
print(m.name)