python装饰器语法糖_Python_日记 装饰器和语法糖

什么是高阶函数?

-- 把函数名当做参数传给另外一个函数,在另外一个函数中通过参数调用执行

#!/usr/bin/python3

deffunc_x(x):return x * 2

deffunc_y(y):return y * 3

deffunc_z(x, y):#等价于 return func_x(5) + func_y(3)

return x(5) + y(3)if __name__ == '__main__':#把函数当做参数,本质上是把函数的内存地址当做参数传递过去,

result =func_z(func_x, func_y)print(result)

什么是装饰器?

-- 在不改变源代码的基础上扩展新需求,装饰器本身也是函数,应用高阶函数实现

-- 把被装饰的函数内存地址当参数传入装饰器函数体,通过参数调用被装饰的函数

装饰器原则:

-- 不改变源代码                         - 因为函数可能在其他地方各种调用,一改动全身

-- 不改变原函数调用顺序           - 源代码有自己的逻辑处理

-- 装饰器又叫做语法糖

装饰器逻辑上格式?

- 高阶函数+嵌套函数

需求:

给某个函数增加一个计算运行时间功能

#!/usr/bin/python3

importtimedef total_time(func): #func = hell_word

def wrapper(): #等价于hell_word()

start_time =time.time()

func()

end_time=time.time()print(end_time - start_time) #打印统计时间

returnwrapper#通过装饰器给hell_word函数装上了统计时间的功能,功能逻辑在装饰器中实现

@total_timedefhell_word():

time.sleep(0.5)print('hello word')if __name__ == '__main__':

hell_word()

相当于下面的函数逻辑

importtime

#装饰器函数

deftotal_time(func):defwrapper():

start_time=time.time()

func()

end_time=time.time()print(end_time -start_time)returnwrapper

defhell_word():

time.sleep(0.5)print('hello word')if __name__ == '__main__':#把函数当做参数传入装饰器函数,然后装饰器函数返回包裹函数wrapper地址,执行装饰器函数本质上执行包裹函数wrapper中逻辑

total_time(hell_word)()

假如传入的函数中有参数如何?

-- 需要在wrapper和func中加入收集参数(*args)或收集字典参数(**kwargs),

-- warps和func可自定义名字,默认如此命名

如果原函数有个返回值,该如何?

-- 如果到func结束 直接在func()前面加return

-- 到func未结束,可以func()结果赋值给一个变量,res = func(*args,**kwargs)到新增逻辑结束后加上 return res

需求:

计算出斐波那契数列中第n个数的值?

求一个共有10个台阶的楼梯,从下走到上面,一次只能迈出1~3个台阶,并且不能后退,有多少中方法?

要求:

通过装饰器实现剪枝函数

如何逻辑整理这个需求?

斐波那契数列(黄金分割数列),从数列的第3项开始,每一项都等于前两项之和

每次迈出都是 1~3 个台阶,剩下就是 7~9 个台阶

如果迈出1个台阶,需要求出后面9个台阶的走法

如果迈出2个台阶,需要求出后面8个台阶的走法

如果迈出3个台阶,需要求出后面7个台阶的走法

此3种方式走法,通过递归方式实现,递归像树,每次递归都生成子节点函数

defjian_zhi(func):#中间字典,判断已经是否求解过

median ={}def wrapper(*args):#假如不在中间字典中,说明没有求解过,添加到字典中去,在的话,直接返回, 将不在递归下去,保证每次递归的唯一性

if args not inmedian:

median[args]= func(*args)returnmedian[args]returnwrapper

@jian_zhideffibonacci(n):if n <= 1:return 1

return fibonacci(n - 1) + fibonacci(n - 2)

@jian_zhidefclimb(n, steps):

count=0#当最后台阶为0的时候,说明最后只是走了一次

if n ==0:

count= 1

#当最后台阶不为0的时候,说明还需要走至少一次

elif n >0:#对三种情况进行分别处理momo

for step insteps:

count+= climb(n -step, steps)#返回每次递归的计数

returncountif __name__ == '__main__':print(climb(10, (1, 2, 3)))print(fibonacci(20))

需求:

实现在装饰器函数中,保留 被装饰函数 的元数据

那,什么是函数的元数据?

在函数对象中保存着一些函数的元数据,如:

f.__name__           函数名

f.__doc__              函数文档

f.__moudle__       函数所属模块名

f.__dict__              属性字典

f.__defaults__       默认参数组

……

在使用装饰器后,在装饰器里访问以上属性时,我们看到的是装饰器函数的元数据

那,如何解决这个需求?

通过 functools中的wraps或update_wrapper方法实现,其中每个方法都可单独实现

importtimefrom functools import(wraps, update_wrapper, WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES)defcount_time(func):"""给目标函数加上计算运行时间统计"""

#这个装上器和update_wrapper一样,默认参数WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES

@wraps(func)def wrapper(*args, **kwargs):

start_time=time.time()#定义result接收函数返回值,并且在装饰函数最后返回回去

resutl = func(*args, **kwargs)print('运行时间:', time.time() -start_time)returnresutl#其中默认参数 WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES

#update_wrapper(wrapper, func)

returnwrapper

@count_timedef add(num=100):"""计算 0~num 累加值,默认num=100"""time.sleep(1)return sum([x for x in range(num + 1)])if __name__ == '__main__':print('函数名:', add.__name__)print('属性字典:', add.__dict__)print('函数默认参数:', add.__defaults__)print('函数所在模块:', add.__module__)print('函数文档:', add.__doc__)#打印两个默认参数

#WRAPPER_ASSIGNMENTS :__module__', '__name__', '__qualname__', '__doc__', '__annotations__

#WRAPPER_UPDATES:__dict__

print(WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES)

result=add()print(result)

需求:

实现一个装饰器,用它来检查被装饰函数的参数类型,装饰器可以通过函数,指明函数参数类型,进行函数调用的时候,传入参数,检测到不匹配时,抛出异常

那,如何解决这个需求?

-- 先要获取函数的签名,并且获得装饰器中参数,然后把函数签名和装饰器中参数对应绑定

-- 把调用函数时候传入的参数和函数签名进行绑定

-- 把实参和装饰器中定义的数据进行类型比较,不匹配抛出异常

from inspect importsignaturedef check_type(*ty_args, **ty_kwargs):defout_wrapper(func):#通过signature方法,获取函数形参:name, age, height

sig =signature(func)#获得装饰器传来的参数, 函数签名与之绑定,字典类型

bind_types = sig.bind_partial(*ty_args, **ty_kwargs).argumentsprint(bind_types)def wrapper(*args, **kwargs):#给执行函数中具体的实参进行和形参进行绑定,形成字典的形式

func_type = sig.bind(*args, **kwargs).arguments.items()print(func_type)#循环形参和实参字典的items()形式

for name, obj infunc_type:if name inbind_types:#判断实参是否是指定类型数据

if notisinstance(obj, bind_types[name]):raise TypeError('%s must be %s' %(name, bind_types[name]))#假如函数有返回值,通过此方法返回函数的返回值

res = func(*args, **kwargs)returnresreturnwrapperreturnout_wrapper#通过装饰器实现对函数参数进行类型检查

@check_type(str, int, float)deffunc(name, age, height):print(name, age, height)if __name__ == '__main__':#正常数据

func('bei_men', 18, 1.75)#错误数据

func('bei_men', '18', 1.75)

案例:

为分析程序内哪些函数执行时间开销较大,我们需定义一个带timeout参数的装饰器

需求:

统计被装饰函数的运行时间

时间大于timeout时,将此次函数调用记录到log日志中

运行时可以修改timeout的值

如何解决这个问题?

定义一个装饰器,计算函数执行时间,并与timeout比较,当大于timeout时候,通过logging模块打印出日志信息

在包裹函数中添加一个函数,通过这个函数来修改timeout变量

在python3中用nonlocal来声明嵌套作用域中的变量引用,在python2中可以通过把timeout参数变成列表,通过列表索引来进行改值

importtimeimportloggingfrom random importrandintdefrun_time(timeout):"""定义检查函数运行时间,并打印对应函数运行时间超出设定时间日志,并支持更改timeout"""

#python2

#timeout = [timeout]

#真正包裹函数

defout_wrapper(func):def wrapper(*args, **kwargs):

start_time=time.time()

result= func(*args, **kwargs)

used_time= time.time() -start_time#对于超出timeout的函数进行日志打印

if used_time >timeout:

msg= '%s: %s > %s' % (func.__name__, used_time, timeout)

logging.warn(msg)#python2

#if used_time > timeout[0]:

#msg = '%s: %s > %s' % (func.__name__, used_time, timeout[0])

#logging.warn(msg)

#return result

returnresult#设置timeout参数值

defset_timeout(value):#声明嵌套域变量,可以更改,python2通过把列表形式进行更改

nonlocal timeout

timeout=value#定义接口

wrapper.set_timeout =set_timeout#python2

#def set_timeout(value):

#timeout[0] = value

#wrapper.set_timeout = set_timeout

returnwrapperreturnout_wrapper

@run_time(1.5)deffunc():#随机有50%的几率程序沉睡1秒

while randint(0, 1):

time.sleep(1)print('func_run')if __name__ == "__main__":for _ in range(10):

func()print('_' * 50)#更改run_time装饰器中timeout参数

func.set_timeout(2)for _ in range(10):

func()

如何逻辑整理?

-- 3层 :一层获得value,二层偷梁换柱,三层逻辑处理

-- 2层:一层偷梁换柱,二层逻辑处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值