python装饰器的案例_python 装饰器案例解析

python 装饰器案例解析

发布时间:2018-02-26 20:38:49编辑:admin阅读(1761)

本文介绍几个装饰器案例,来分析装饰器是如何调用的

获取函数运行时间的例子

写装饰器,不可以一步到位,要慢慢一点一点的来

先写好2个函数import time

def test1():

time.sleep(1)

print('in the test1')

def test2():

time.sleep(2)

print('in the test2')

test1()

test2()

执行输出

in the test1

in the test2

在不修改源代码的情况下,新增一个功能呢?

这个时候,需要用到 高阶函数import time

def deco(func):

start_time = time.time()

func()

stop_time = time.time()

print('the func run time is %s' % (stop_time - start_time))

def test1():

time.sleep(1)

print('in the test1')

def test2():

time.sleep(2)

print('in the test2')

deco(test1)

deco(test2)

执行输出

in the test1

the func run time is 1.0009195804595947

in the test2

the func run time is 2.0000431537628174

注意:

执行的时候,不能写deco(test1()),为什么呢?这样写,是把test1函数执行的结果,传给deco了。

deco函数,不需要执行结果,它需要一个函数即可。

Pycharm编辑器写代码的时候,有自动补全功能,切记这里,要把括号删掉才行。

上面实现了显示执行时间的功能,下面考虑一个问题,如何在此基础上,直接执行

test1()和test2() 就可以实现上面的功能

需要用到变量的引用def deco(func):

start_time = time.time()

func()

stop_time = time.time()

print('the func run time is %s' % (stop_time - start_time))

def test1():

time.sleep(1)

print('in the test1')

def test2():

time.sleep(2)

print('in the test2')

test1 = deco(test1)

test2 = deco(test2)

test1()

test2()

执行报错

TypeError: 'NoneType' object is not callable

因为deco没有return,无法得到函数内存地址

再改一下import time

def deco(func):

start_time = time.time()

#返回函数内存地址

return func

stop_time = time.time()

print('the func run time is %s' % (stop_time - start_time))

def test1():

time.sleep(1)

print('in the test1')

def test2():

time.sleep(2)

print('in the test2')

test1 = deco(test1)

test2 = deco(test2)

test1()

test2()

执行输出

in the test1

in the test2

从结果可以看出,函数的调用方式没有变,执行结果也没有变。搞了半天,啥都没干。

因为deco中直接returun了,所以打印时间没有输出。

上面的应用都是高阶函数,还缺嵌套函数,就成了

下面写一个嵌套函数。def timer():

def deco():

pass

能不能把嵌套函数的形式融入到deco函数中呢?

把deco函数的代码直接拷贝进来,最后return deco

一个函数只有一个return,把中间的return修改为func()

将func参数移动到函数最上层def timer(func):

def deco():

start_time = time.time()

func()

stop_time = time.time()

print('the func run time is %s' % (stop_time - start_time))

return deco

完整代码如下:import time

def timer(func): #time(test1) func=test1

def deco():

start_time = time.time()

func() #run test1()

stop_time = time.time()

print('the func run time is %s' % (stop_time - start_time))

return deco

def test1():

time.sleep(1)

print('in the test1')

def test2():

time.sleep(2)

print('in the test2')

print(timer(test1))

执行输出

function timer.

结果返回deco函数的内存地址

有了函数的内存地址,把它赋值给一个变量,执行变量就可以了

print(timer(test1))改成test1 = timer(test1)

test1()

执行输出

in the test1

the func run time is 1.0003840923309326

这里,效果就实现了,源代码和执行方式都没有改变。

注意: 最后的test1()行函数,已经不是原来的函数了,而是被装饰过的函数。

执行函数,需要2个步骤,太麻烦了,这不是最终效果

python 提供一个语法,用来执行装饰器函数,语法@函数名

被装饰的函数名

这一句,需要加在被装饰函数的上一行

我删除了test2(),最终完整代码如下:#!/usr/bin/env python

# coding: utf-8

__author__ = 'www.py3study.com'

import time

def timer(func): #timer(test) func=test1

def deco():

start_time = time.time()

func() #run test1()

stop_time = time.time()

print('the func run time is %s' % (stop_time - start_time))

return deco

@timer #test1=timer(test1)

def test1():

time.sleep(1)

print('in the test1')

test1()

执行输出

in the test1

the func run time is 1.0006184577941895

test1()函数上面的@timer

就相当于test1 = timer(test1)

注意:上面写的装饰器,还不够完美

举个例子,再加一个函数,去装饰它#!/usr/bin/env python

# coding: utf-8

__author__ = 'www.py3study.com'

import time

def timer(func):

def deco():

start_time = time.time()

func()

stop_time = time.time()

print('the func run time is %s' % (stop_time - start_time))

return deco

@timer

def test1():

time.sleep(1)

print('in the test1')

@timer

def test2(name):

print("test",name)

test1()

test2("zhang")

执行报错

TypeError: test2() missing 1 required positional argument: 'name'

为什么呢?

test2上面的@timer就相当于test2 = timer(test2)

timer(test2) -> 调用deco() -> 调用func() ->调用原test2(name)

注意,调用原test2函数的时候,需要传一个参数才行,而func()调用它的时候,没法传参数,所以程序报错。

为了解决传参的问题,需要调整一下deco函数,要求能接受参数。由于被装饰的函数,千奇百怪,有参数,没参数的都存在。使用*args,**kwargs就可以表示任意的参数。

最后终极代码如下:#!/usr/bin/env python

# coding: utf-8

__author__ = 'www.py3study.com'

import time

def timer(func):

def deco(*args,**kwargs):

start_time = time.time()

func(*args,**kwargs)

stop_time = time.time()

print('the func run time is %s' % (stop_time - start_time))

return deco

@timer

def test1():

time.sleep(1)

print('in the test1')

@timer

def test2(name):

time.sleep(2)

print("test",name)

test1()

test2("zhang")

执行输出

in the test1

the func run time is 1.000878095626831

test zhang

the func run time is 2.0003161430358887

网页登陆

代码如下:#!/usr/bin/env python

# coding: utf-8

__author__ = 'www.py3study.com'

import time

user,passwd = 'zhang','abc123'

def auth(func):

def wrapper(*args,**kwargs):

username = input("username:").strip()

password = input("password:").strip()

if user == username and passwd == password:

print("\033[32;1mUser has passed authentication\033[0m")

func(*args,**kwargs)

else:

exit("\033[31;1mInvalid username or password\033[0m")

return  wrapper

def index():

print("welcome to index page")

@auth

def home():

print("welcome to home page")

@auth

def bbs():

print("welcome to bbs page")

index()

home()

bbs()

执行输出

134fac9a7d8f46ecf45cca746c2241ca.png

输出了2次用户名和密码

为什么呢?因为home和bbs页面,需要登录才能访问。

下面加一个验证方式#!/usr/bin/env python

# coding: utf-8

__author__ = 'www.py3study.com'

import time

user,passwd = 'zhang','abc123'

def auth(auth_type):

print("auth func:",auth_type)

def outer_wrapper(func):

def wrapper(*args, **kwargs):

print("wrapper func args:",*args, **kwargs)

username = input("username:").strip()

password = input("password:").strip()

if user == username and passwd == password:

print("\033[32;1mUser has passed authentication\033[0m")

res = func(*args, **kwargs)

print("---after authentication")

return res

else:

exit("\033[31;1mInvalid username or password\033[0m")

return wrapper

return outer_wrapper

def index():

print("welcome to index page")

@auth(auth_type="local")

def home():

print("welcome to home page")

@auth(auth_type="ldap")

def bbs():

print("welcome to bbs page")

index()

home()

bbs()

执行输出

79715c99026df2acd32e7a75f75815b3.png

现在还没有判断是哪种方式

完整代码如下:#!/usr/bin/env python

# coding: utf-8

__author__ = 'www.py3study.com'

import time

user,passwd = 'zhang','abc123'

def auth(auth_type):

#print("auth func:",auth_type)

def outer_wrapper(func):

def wrapper(*args, **kwargs):

#print("wrapper func args:",*args, **kwargs)

if auth_type == "local":

username = input("username:").strip()

password = input("password:").strip()

if user == username and passwd == password:

print("\033[32;1mUser has passed authentication\033[0m")

res = func(*args, **kwargs)

print("---after authentication")

return res

else:

exit("\033[31;1mInvalid username or password\033[0m")

elif auth_type == "ldap":

print("This is LDAP,I can't do it")

pass

return wrapper

return outer_wrapper

def index():

print("welcome to index page")

@auth(auth_type="local")

def home():

print("from home page")

@auth(auth_type="ldap")

def bbs():

print("from bbs page")

index()

home()

bbs()

执行输出

6f16f9b71ad723c82072c9a57da88125.png

执行bbs,采用的是ldap方式,我就直接输出了一段话,判断逻辑不会写啊!

关键字:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值