我的编程空间,编程开发者的网络收藏夹
学习永远不晚

详解Python函数式编程之装饰器

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

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

详解Python函数式编程之装饰器

一、装饰器的本质:

装饰器(decorator)本质是函数闭包(function closure)的语法糖(Syntactic sugar)

函数闭包(function closure):

函数闭包是函数式语言(函数是一等公民,可作为变量使用)中的术语。函数闭包:一个函数,其参数和返回值都是函数,用于增强函数功能面向切面编程(AOP)

import time
# 控制台打印100以内的奇数:
def print_odd():
    for i in range(100):
        if i % 2 == 1:
            print(i)
# 函数闭包:用于增强函数func:给函数func增加统计时间的功能:
def count_time_wrapper(func):
    def improved_func():
        start_time = time.time()
        func()
        end_time = time.time()
        print(f"It takes {end_time - start_time} S to find all the odds in range !!!")
    return improved_func
if __name__ == '__main__':
    # 调用count_time_wrapper增强函数
    print_odd = count_time_wrapper(print_odd)
    print_odd()

闭包本质上是一个函数,闭包函数的传入参数和返回值都是函数,闭包函数得到返回值函数是对传入函数增强后的结果。

日志装饰器:

def log_wrapper(func):
    """
    闭包,用于增强函数func: 给func增加日志功能
    """
    def improved_func():
        start_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))  # 起始时间
        func()  # 执行函数
        end_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))  # 结束时间
        print("Logging: func:{} runs from {} to {}".format(func.__name__, start_time, end_time))
    return improved_func

二、装饰器使用方法:

通过装饰器进行函数增强,只是一种语法糖,本质上跟上个程序(使用函数闭包)完全一致。

import time
# 函数闭包:用于增强函数func:给函数func增加统计时间的功能:
def count_time_wrapper(func):
    def improved_func():
        start_time = time.time()
        func()
        end_time = time.time()
        print(f"It takes {end_time - start_time} S to find all the odds in range !!!")
    return improved_func
# 控制台打印100以内的奇数:
@count_time_wrapper  # 添加装饰器
def print_odd():
    for i in range(100):
        if i % 2 == 1:
            print(i)
if __name__ == '__main__':
    # 使用  @装饰器(增强函数名) 给当前函数添加装饰器,等价于执行了下面这条语句:
    # print_odd = count_time_wrapper(print_odd)
    print_odd()

装饰器在第一次调用被装饰函数时进行增强,只增强一次,下次调用仍然是调用增强后的函数,不会重复执行增强!

保留函数参数和返回值的函数闭包:

  • 之前所写的函数闭包,在增强主要功能函数时,没有保留原主要功能函数的参数列表和返回值。
  • 一个保留参数列表和返回值的函数闭包写法:
def general_wrapper(func):
    def improved_func(*args, **kwargs):
        # 增强函数功能:
        ret = func(*args, **kwargs)
        # 增强函数功能:
        return ret
    return improved_func

优化装饰器(参数传递、设置返回值): 

import time
# 函数闭包:用于增强函数func:给函数func增加统计时间的功能:
def count_time_wrapper(func):
    # 增强函数:
    def improved_func(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"It takes {end_time - start_time} S to find all the odds in range !!!")
        # 原函数返回值
        return result
    return improved_func
# 计算0-lim奇数之和:
@count_time_wrapper
def count_odds(lim):
    cnt = 0
    for i in range(lim):
        if i % 2 == 1:
            cnt = cnt + i
    return cnt
if __name__ == '__main__':
    result = count_odds(10000000)
    print(f"计算结果为{result}!")

三、多个装饰器的执行顺序:

# 装饰器1:
def wrapper1(func1):
    print("set func1")  # 在wrapper1装饰函数时输出
    def improved_func1(*args, **kwargs):
        print("call func1")  # 在wrapper1装饰过的函数被调用时输出
        func1(*args, **kwargs)
        return None
    return improved_func1
# 装饰器2:
def wrapper2(func2):
    print("set func2")  # 在wrapper2装饰函数时输出
    def improved_func2(*args, **kwargs):
        print("call func1")  # 在wrapper2装饰过的函数被调用时输出
        func2(*args, **kwargs)
        return None
    return improved_func2
@wrapper1
@wrapper2
def original_func():
    pass
if __name__ == '__main__':
    original_func()
    print("------------")
    original_func()

这里得到的执行结果是,wrapper2装饰器先执行,原因是因为:程序从上往下执行,当运行到:

@wrapper1
@wrapper2
def original_func():
    pass

这段代码时,使用函数闭包的方式解析为:

original_func = wrapper1(wrapper2(original_func))

所以先进行wrapper2装饰,然后再对被wrapper2装饰完成的增强函数再由wrapper1进行装饰,返回最终的增强函数。

四、创建带参数的装饰器:

装饰器允许传入参数,一个携带了参数的装饰器将有三层函数,如下所示:

import functools
def log_with_param(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print('call %s():' % func.__name__)
            print('args = {}'.format(*args))
            print('log_param = {}'.format(text))
            return func(*args, **kwargs)
        return wrapper
    return decorator
@log_with_param("param!!!")
def test_with_param(p):
    print(test_with_param.__name__)
if __name__ == '__main__':
    test_with_param("test")

将其 @语法 去除,恢复函数调用的形式:

# 传入装饰器的参数,并接收返回的decorator函数
decorator = log_with_param("param!!!")
# 传入test_with_param函数
wrapper = decorator(test_with_param)
# 调用装饰器函数
wrapper("I'm a param")

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容! 

免责声明:

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

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

详解Python函数式编程之装饰器

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python函数式编程之装饰器

原则:对修改是封闭的,对扩展是开放的,方法:一般不修改函数或者类,而是扩展函数或者类一:装饰器 允许我们将一个提供核心功能的对象和其他可以改变这个功能的对象’包裹‘在一起, 使用装饰对象的任何对象与装饰前后该对象的交互遵循完全相
2023-01-30

python装饰器1:函数装饰器详解

装饰器1:函数装饰器装饰器2:类装饰器装饰器3:进阶先混个眼熟谁可以作为装饰器(可以将谁编写成装饰器):函数方法实现了__call__的可调用类装饰器可以去装饰谁(谁可以被装饰):函数方法类基础:函数装饰器的表现方式假如你已经定义了一个函数
2023-01-30

python之装饰器(函数)

1. 装饰器   遵循的原则:     开闭原则:   对功能的扩展开放  对代码的修改是封闭# 通用装饰器写法# 存在的意义: 在不破坏原有函数和原有函数调用的基础上,给函数添加新的功能.def wrapper(fn): #
2023-01-30

Python函数式编程装饰器的示例分析

这篇文章给大家分享的是有关Python函数式编程装饰器的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、装饰器的本质:装饰器(decorator)本质是函数闭包(function closure)的语法
2023-06-29

python中函数总结之装饰器闭包详解

1、前言 函数也是一个对象,从而可以增加属性,使用句点来表示属性。 如果内部函数的定义包含了在外部函数中定义的对象的引用(外部对象可以是在外部函数之外),那么内部函数被称之为闭包。 2、装饰器 装饰器就是包装原来的函数,从而在不需要修改原来
2022-06-04

详解Python装饰器之@property

一、property() 函数讲解 了解 @property 装饰器之前,我们首先要了解内置函数的 property()。class property(fget=None, fset=None, fdel=None, doc=None)描述
2022-06-02

Python 3 之 装饰器详解

------------ 装饰器 -----------------------------------------------------什么是装饰器装饰器是为函数和类指定管理代码的一种方式。装饰器本身的形式是处理其他的可调用对象的可调用
2023-01-31

浅析Python编写函数装饰器

编写函数装饰器 本节主要介绍编写函数装饰器的相关内容。跟踪调用 如下代码定义并应用一个函数装饰器,来统计对装饰的函数的调用次数,并且针对每一次调用打印跟踪信息。class tracer: def __init__(self,func): s
2022-06-04

深入了解Python装饰器函数

本篇文章给大家带来了关于python的相关知识,其中主要整理了装饰器函数的相关问题,包括了装饰器的形成过程、本质与功能、进阶与优化等等内容,下面一起来看一下,希望对大家有帮助。假如我写了一个函数 fdef f(): print(hello)之后我想知道这段函数执行所要的时间,这好办,我只要将代码改为如下就行import timedef f(): start = time.time()
2022-06-26

Python函数装饰器--实例讲解

一、装饰器定义:1.装饰器的本质为函数;2.装饰器是用来完成被修饰函数的附加功能的所以:装饰器是用来完成被修饰函数附属功能的函数装饰器的要求:1.不能修改被修饰函数的源代码;2.不能更改被修饰函数的运行方式;3.上述两者缺一不可。二、装饰器
2023-01-31

Python函数式编程之闭包

-------------------------函数式编程之*******闭包------------------------Note:一:简介 函数式编程不是程序必须要的,但是对于简化程序有很重要的作用。 Python中一切
2023-01-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录