日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

装饰器及例题分析

發(fā)布時(shí)間:2023/11/27 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 装饰器及例题分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

知識(shí)點(diǎn):

裝飾器的定義:
- 裝飾器的實(shí)現(xiàn)是函數(shù)里面嵌套函數(shù);
- 裝飾器的本質(zhì)是一個(gè)函數(shù), 它可以讓其他函數(shù)在不需要做任何代碼改動(dòng)的前提下增加額外的功能;
- 裝飾器需要傳遞一個(gè)函數(shù), 返回值也是一個(gè)函數(shù)對(duì)象.

1、map函數(shù)

def f(x):return x * x"""map()傳入的第一個(gè)參數(shù)是一個(gè)函數(shù),第二個(gè)參數(shù)是一個(gè)序列,第二個(gè)序列作為第一個(gè)參數(shù)的輸入值
也就是說(shuō)第二個(gè)參數(shù)調(diào)用了第一個(gè)函數(shù)
"""print map(f, [1, 2, 3, 4])

2、匿名函數(shù)

#上面的函數(shù)也可以用一條語(yǔ)句代替,即匿名函數(shù)lambdax:

print map(lambda x: x * x, [1, 2, 3, 4])

3、帶有參數(shù)的裝飾器:

import functools
import time# 打印當(dāng)前的時(shí)間
print time.ctime()def log(name):def add_log(fun):@functools.wraps(fun)def wrapper(*args, **kwargs):start_time = time.time()res = fun(*args, **kwargs)end_time = time.time()print '<%s> [%s] 函數(shù)名:%s,運(yùn)行時(shí)間:%.5f,運(yùn)行返回值結(jié)果:%d' %(name, time.ctime(), fun.__name__, end_time - start_time, res)return resreturn wrapperreturn add_log@log('lily')
def add(x,y):time.sleep(1)return x+yprint add(1,2)

4、多個(gè)裝飾器的執(zhí)行順序

#定義兩個(gè)裝飾器,將兩個(gè)裝飾器給函數(shù),探究其中調(diào)用的先后順序

def decorator_a(func):print 'Get in decorator_a'def inner_a(*args, **kwargs):print 'Get in inner_a'res = func(*args, **kwargs)return resreturn inner_adef decorator_b(func):print 'Get in decorator_b'def inner_b(*args, **kwargs):print 'Get in inner_b'res = func(*args, **kwargs)return resreturn inner_b# 當(dāng)有多個(gè)裝飾器時(shí),從下到上調(diào)用裝飾器
@decorator_a
@decorator_b
def f(x):print 'Get in f'return x * 2f(1)

?

總結(jié):

從運(yùn)行結(jié)果可以看出,若將decorator_a和decorator_b按順序給函數(shù),則裝飾器外部為從下島上調(diào)用裝飾器,內(nèi)部仍按順序調(diào)用。

例題分析:

1、多個(gè)裝飾器的應(yīng)用

要求:查看若要實(shí)現(xiàn)相同的功能python內(nèi)置函數(shù)和自己編寫(xiě)的函數(shù)哪個(gè)運(yùn)行時(shí)間更少

裝飾器需求:獲取每個(gè)函數(shù)的執(zhí)行時(shí)間

1.函數(shù)執(zhí)行之前計(jì)算時(shí)間

2.函數(shù)執(zhí)行之后計(jì)算時(shí)間

3.運(yùn)行時(shí)間=執(zhí)行后時(shí)間-執(zhí)行前時(shí)間

問(wèn)題1:被裝飾的函數(shù)有返回值的時(shí)候怎么辦?

問(wèn)題2:如何保留被裝飾函數(shù)的函數(shù)名和幫助文檔信息

import functools
import random
import string
import time"""導(dǎo)入模塊的快捷鍵為Alt+Enter并選擇"""
li = [random.choice(string.ascii_letters) for i in range(100)]def timeit(fun):"""裝飾器"""@functools.wraps(fun)def wrapper(*args, **kwargs):  # 接收可變參數(shù)和關(guān)鍵字參數(shù)"""這是一個(gè)wrapper函數(shù)"""# args:元組 kwargs:字典# 函數(shù)執(zhí)行之前start_time = time.time()# 執(zhí)行函數(shù)# 接收被裝飾函數(shù)的返回值res = fun(*args, **kwargs)# 函數(shù)執(zhí)行之后end_time = time.time()print '運(yùn)行的時(shí)間為:%.6f' % (end_time - start_time)return resreturn wrapper@timeit
def con_add():s = ''for i in li:s += (i + ',')print s@timeit
def join_add():print ','.join(li)@timeit
def fun_list(n):"""這是fun_list函數(shù),被timeit裝飾"""return [2 * i for i in range(n)]@timeit
def fun_map(n):"""這是fun_map函數(shù)"""return list(map(lambda x: x * 2, range(n)))# 匿名函數(shù)
# map傳入的第一個(gè)參數(shù)為一個(gè)函數(shù),第二個(gè)為一個(gè)序列con_add()
join_add()
print fun_list(50000)
print fun_map(50000)#保留被裝飾函數(shù)的函數(shù)名和幫助文檔信息
print fun_list.__name__
print fun_list.__doc__

總結(jié):從上面的運(yùn)行時(shí)間可以看出:

用python的內(nèi)置函數(shù)比自己編寫(xiě)的函數(shù)運(yùn)行時(shí)間少,所以我們?cè)谡{(diào)用函數(shù)的時(shí)候盡量使用python的內(nèi)置函數(shù)。

?

2、

在我們實(shí)際的應(yīng)用中,會(huì)應(yīng)用到多個(gè)裝飾器,例如: 先驗(yàn)證是否登陸成功再驗(yàn)證權(quán)限的方法

要求:用戶登陸驗(yàn)證的裝飾器 is_login

?????????? 1.如果用戶登陸成功,則執(zhí)行被裝飾的函數(shù)

?????????? 2.如果用戶登陸不成功,則執(zhí)行登陸函數(shù)

import functools
# 讓函數(shù)統(tǒng)一
import inspectdef is_root(fun):@functools.wraps(fun)def wrapper(*args, **kwargs):inspect_res = inspect.getcallargs(fun, *args, **kwargs)print 'inspect_res的返回值:%s' % inspect_resif inspect_res.get('name') == 'root':res = fun(*args, **kwargs)return reselse:print 'Error:no perminssion add student'return wrapperdef is_login(fun):@functools.wraps(fun)def warrper(*args, **kwargs):if args[0] in login_session:res = fun(*args, **kwargs)return reselse:print 'Error:%s未登陸'return warrper@is_login
@is_root
def add_student(name):print '添加學(xué)生信息'login_session = ['root', 'admin', 'redhat']
# 調(diào)用函數(shù)
add_student('root')

3、

要求:用戶登陸驗(yàn)證的裝飾器 is_login

?????????? 1.如果用戶登陸成功,則執(zhí)行被裝飾的函數(shù)

?????????? 2.如果用戶登陸不成功,則執(zhí)行登陸函數(shù)

import functoolslogin_users = ['admin', 'root']def is_login(fun):@functools.wraps(fun)def wrapper(*args, **kwargs):# 判斷寫(xiě)博客這個(gè)用戶是否登陸成功if kwargs.get('name') in login_users:res = fun(*args, **kwargs)return reselse:res = login()return resreturn wrapperdef login():return '登陸。。。'@is_login
def writeBlog(name):return '編寫(xiě)博客。。'print writeBlog(name='admin')

若最后調(diào)用函數(shù)時(shí)為:

print? writeBlog(name='admin')

4、

要求:

創(chuàng)建裝飾器, 要求如下:

1. 創(chuàng)建add_log裝飾器, 被裝飾的函數(shù)打印日志信息;

2. 日志格式為: [字符串時(shí)間] 函數(shù)名: xxx, 運(yùn)行時(shí)間:xxx, 運(yùn)行返回值結(jié)果:xxx

import time
import functools
#print time.ctime()def add_log(fun):@functools.wraps(fun)def wrapper(*args,**kwargs):start_time = time.time()res = fun(*args,**kwargs)end_time = time.time()print '[%s] 函數(shù)名:%s,運(yùn)行時(shí)間:%.5f,運(yùn)行返回值結(jié)果:%d' %(time.ctime(),fun.__name__,end_time-start_time,res)return resreturn wrapper@add_log
def add(x,y):time.sleep(1)return x+yprint add(1,2)

5、

編寫(xiě)裝飾器required_ints, 條件如下:1). 確保函數(shù)接收到的每一個(gè)參數(shù)都是整數(shù);2). 如果參數(shù)不是整形數(shù), 打印 TypeError:參數(shù)必須為整形import functoolsdef required_ints(fun):@functools.wraps(fun)def wrapper(*args, **kwargs):for i in args:if not isinstance(i, int):print 'TypeError:參數(shù)必須為整形'breakelse:res = fun(*args, **kwargs)return resreturn wrapper@required_ints
def add(a, b):return a + b@required_ints
def myMax(a,b,c,d):return max(a,b,c,d)print add(1,2)
print myMax(1,2,3,4)

6、

要求:編寫(xiě)裝飾器required_types, 條件如下:

1). 當(dāng)裝飾器為@required_types(int,float)確保函數(shù)接收到的每一個(gè)參數(shù)都是int或者float類型;

2). 當(dāng)裝飾器為@required_types(list)確保函數(shù)接收到的每一個(gè)參數(shù)都是list類型;

3). 當(dāng)裝飾器為@required_types(str,int)確保函數(shù)接收到的每一個(gè)參數(shù)都是str或者int類型;

4). 如果參數(shù)不滿足條件, 打印 TypeError:參數(shù)必須為xxxx類型

import functoolsdef required_types(*kinds):def required_ints(fun):@functools.wraps(fun)def wrapper(*args, **kwargs):for i in args:if not isinstance(i, kinds):print 'TypeError:參數(shù)必須為',kindsbreakelse:res = fun(*args, **kwargs)return resreturn wrapperreturn required_ints@required_types(float,float)
def add(a, b):return a + bprint add(1.1,3)

總結(jié)

以上是生活随笔為你收集整理的装饰器及例题分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

歡迎分享!

轉(zhuǎn)載請(qǐng)說(shuō)明來(lái)源于"生活随笔",并保留原作者的名字。

本文地址:装饰器及例题分析