文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

初窥Python(五)——python中

2023-01-31 04:59

关注



1. 介绍

decorator是用来在代码运行期间动态增加功能的,本质上是一个返回函数的高阶函数。假设现在有这样一种需求,即在每个函数调用前记录日志,记录被调用的函数名称,可以这样实现:

def log(func):
    def wrapper(*args, **kwargs):
        print "CALL %s()" % func.__name__
        return func(*args, **kwargs)
    return wrapper

def sayHi():
    print "Hi, Buddy."

def sayHello():
    print "Hello, Buddy."

# 调用函数,记录日志
log(sayHi)()
# 输出为
# CALL sayHi()
# Hi, Buddy.
log(sayHello)()
# 输出为
# CALL sayHello()
# Hello, Buddy.

这种方法确实实现了记录日志的功能,但每次这么调用未免太过繁琐,decorator因此出现。

2. 使用

其实,之前定义的log函数即为一个decorator,只是使用方式不正确:

@log
def sayHi():
    print "Hi, Buddy."

sayHi()
# 输出为
# CALL sayHi()
# Hi, Buddy.

@log
def sayHello():
    print "Hello, Buddy."

sayHello()
# 输出为
# CALL sayHello()
# Hello, Buddy.

可以看到,使用decorator非常简单方便,def sayHi():前的@log相当于将sayHi作为参数传入log函数中,并将返回值赋给sayHi,即:

sayHi = log(sayHi)

但是细心的读者不难发现,这样一来函数sayHi__name__属性发生变化,由之前的sayHi变为wrapper,使用python内置的functools.wraps方法可以解决这一问题,改造后的decorator如下:

import functools 

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print "CALL %s()" % func.__name__
        return func(*args, **kwargs)
    return wrapper

让我们更进一步,使用三层嵌套的decorator,允许再多传入一次参数:

import functools

def log(text="CALL")
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print "%s %s()" % (text, func.__name__)
            return func(*args, **kwargs)
        return wrapper
    return decorator

这次我们可以选择传入一个表示函数运行状态的字符串,由于多了一层嵌套,使用时也会有些变化:

@log("EXECUTE")
def sayHi():
    print "Hi, Buddy."

sayHi()
# 输出为
# EXECUTE sayHi()
# Hi, Buddy.

修改过后嵌套使用为:

sayHi = log("EXECUTE")(sayHi)

3. 拓展

3.1

修改log函数,使该decorator既可以通过

@log

使用,又可以通过

@log("EXECUTE")

使用:

import functools

def log(text="CALL"):
    if callable(text):
        func = text
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print "CALL %s()" % func.__name__
            return func(*args, **kwargs)
    else:
        def decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                print "%s %s()" % (text, func.__name__)
                return func(*args, **kwargs)
            return wrapper
        return decorator

两种使用方式:

@log
def sayHi():
    print "Hi, Buddy."

sayHi()
# 输出为
# CALL sayHi()
# Hi, Buddy.

@log("EXECUTE")
def sayHello():
    print "Hello, Buddy."

sayHello()
# 输出为
# EXECUTE sayHello()
# Hello, Buddy.
3.2

修改log函数,使该decorator在函数调用前及函数调用后分别输出一条日志:

import functools

def log(func):
    def wrapper(*args, **kwargs):
        print "CALL BEGINNING"
        call = func(*args, **kwargs)
        print "CALL ENDING"
        return call
    return wrapper

使用该decorator

@log
def sayHi():
    print "Hi, Buddy."

sayHi()
# 输出为
# CALL BEGINING
# Hi, Buddy.
# CALL ENDING

参考资料:

廖雪峰的官方网站

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯