前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python 装饰器案例解析

python 装饰器案例解析

作者头像
py3study
发布2018-08-02 16:13:48
2730
发布2018-08-02 16:13:48
举报
文章被收录于专栏:python3python3

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

获取函数运行时间的例子

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

先写好2个函数

代码语言:javascript
复制
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

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

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

代码语言:javascript
复制
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() 就可以实现上面的功能

需要用到变量的引用

代码语言:javascript
复制
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,无法得到函数内存地址

再改一下

代码语言:javascript
复制
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了,所以打印时间没有输出。

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

下面写一个嵌套函数。

代码语言:javascript
复制
def timer():
    def deco():
        pass

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

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

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

将func参数移动到函数最上层

代码语言:javascript
复制
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

完整代码如下:

代码语言:javascript
复制
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))改成

代码语言:javascript
复制
test1 = timer(test1)
test1()

执行输出

in the test1

the func run time is 1.0003840923309326

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

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

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

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

代码语言:javascript
复制
@函数名
被装饰的函数名

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

我删除了test2(),最终完整代码如下:

代码语言:javascript
复制
#!/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

就相当于

代码语言:javascript
复制
test1 = timer(test1)

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

举个例子,再加一个函数,去装饰它

代码语言:javascript
复制
#!/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就相当于

代码语言:javascript
复制
test2 = timer(test2)

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

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

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

最后终极代码如下:

代码语言:javascript
复制
#!/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

网页登陆

代码如下:

代码语言:javascript
复制
#!/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()

执行输出

blob.png
blob.png

输出了2次用户名和密码

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

下面加一个验证方式

代码语言:javascript
复制
#!/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()

执行输出

blob.png
blob.png

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

完整代码如下:

代码语言:javascript
复制
#!/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()

执行输出

blob.png
blob.png

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-02-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档