Python-装饰器上下五千年和前世今生

  装饰器上下五千年和前世今生,这里我们始终要问,装饰器为何产生?装饰器产生解决了什么问题?什么样的需求推动了装饰器的产生?思考问题的时候,始终要问,为什么要这样,而不是那样或者其他样。这里我不先说,也不直接把装饰器的最终样子摆出来,而是说说装饰器发展过程,从这些过程中知道,不是技术推动技术的发展,而是解决这个需求推动技术的产生。接下来一步步构建装饰器产生的过程,从最原始的方向来到最新的状态来解说装饰器为何产生,装饰器产生的过程是如何演变的。

下面是一段简代码,实现的功能是暂停1秒,然后再打印一句问好"Hai, 北门吹雪"

import time

def bei_men_chui_xue():
    time.sleep(1)
    print("Hai, 北门吹雪")

bei_men_chui_xue()

这里需求来了,谁谁谁,总是在提需求,杀了祭天。

哎呀,在这个功能上在添加一个小小的功能,就是一个小小功能,输出一下这个功能的运行时间,不难吧?

默默的掏出身后的板砖,啪的一下拍在桌子上,昨天晚上你不是这样说的,说好不改需求的,今天早上就翻脸了?

好吧,我默默的去改需求了,提交了方案 1

import time

def bei_men_chui_xue():
    time.sleep(1)
    print("Hai, 北门吹雪")

start_time = time.time()
bei_men_chui_xue()
print("run time:", time.time() - start_time)

虽然实现了这个需求,但是这个直接嵌入代码逻辑,把功能代码逻辑包围了起来,看起来不够优雅,改得好看点好么?

好吧,我又默默器去修改需求了,提交了方案2

import time

def bei_men_chui_xue():
    time.sleep(1)
    print("Hai, 北门吹雪")

def get_run_time(func):
    start_time = time.time()
    func()
    end_time = time.time()
    print(end_time - start_time)

# 高阶函数,已经很优雅的解决方案
get_run_time(bei_men_chui_xue)

很好,使用了高阶函数,居然知道Python中一切皆对象的原理,把获取时间的功能封装成一个函数,试试用闭包去实现?

好吧,我又默默器去修改需求了,提交了方案3

import time

def bei_men_chui_xue():
    time.sleep(1)
    print("Hai, 北门吹雪")

def get_run_time(func):
    def wrapper():
        start_time = time.time()
        func()
        end_time = time.time()
        print(end_time - start_time)
    return wrapper

# 闭包解决方案,看起来方案2远比这个优雅
f = get_run_time(bei_men_chui_xue)
f()

嗯,非常好,我也觉得方案2好,但是你修改了源码,改变了源码的执行逻辑,尝试不改变源码逻辑?

好吧,我又默默器去修改需求了,提交了方案4

import time

def get_run_time(func):
    def wrapper():
        start_time = time.time()
        func()
        end_time = time.time()
        print(end_time - start_time)
    return wrapper

@get_run_time
def bei_men_chui_xue():
    time.sleep(1)
    print("Hai, 北门吹雪")

# 装饰器解决方案,前面的语法糖才是装饰器核心
bei_men_chui_xue()

不错不错,装饰器把被装饰函数传递进装饰器,调用源函数其实本质上调用装饰器中的wrapper函数,我想在原函数传递进去参数,如何?

好吧,我又默默器去修改需求了,提交了方案5

import time

def get_run_time(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print(end_time - start_time)
    return wrapper

@get_run_time
def bei_men_chui_xue(name):
    time.sleep(1)
    print("Hai, %s" % name)

# 解决装饰的函数有变量
bei_men_chui_xue("北门吹雪")

很好,很好,通过往装饰器中传递 *args **kwargs参数完成向原函数传递参数,我想获得一下原函数的返回值?如被装饰函数的返回值?

好吧,我又默默器去修改需求了,提交了方案6

import time

def get_run_time(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        r = func(*args, **kwargs)
        end_time = time.time()
        run_time = end_time - start_time
        print(run_time)
        # 被装饰函数返回值
        return r
    return wrapper

@get_run_time
def bei_men_chui_xue(name):
    time.sleep(1)
    return "Hai, %s" % name

# 解决装饰的函数有变量
r = bei_men_chui_xue("北门吹雪")
print(r)

功能还需要改动,我不想输出其运行时间,可以通过向装饰器中传入参数,如果运行时间超过这个数打印已经超时?

好吧,我又默默器去修改需求了,提交了方案7

import time

def get_run_time(time_out):
    def out_wrapper(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            r = func(*args, **kwargs)
            end_time = time.time()
            # 获取运行时间
            run_time = end_time - start_time
            # 检查程序运行时间是否超时
            if run_time > time_out:
                print("运行时间已经超时")
            # 被装饰函数返回值
            return r
        return wrapper
    return out_wrapper

@get_run_time(time_out=1)
def bei_men_chui_xue(name):
    time.sleep(1)
    return "Hai, %s" % name

bei_men_chui_xue("北门吹雪")
# 获取返回值
r = bei_men_chui_xue("北门吹雪")
print(r)

完美,这个才是五彩斑斓的黑,加个鸡腿

从这个过程中可以看出,被装饰函数运行时候其实运行的是装饰器内部wrapper函数,通过函数闭包实现对一些参数状态的保存,从而实现各种需求的装饰器

原文地址:https://www.cnblogs.com/2bjiujiu/p/9135290.html

时间: 2024-10-12 20:15:05

Python-装饰器上下五千年和前世今生的相关文章

python装饰器系列(五)

带参数的装饰器的应用: 比如有一个函数,只有在对有许可权限的用户开放,执行此函数的用户没有在认证列表里的,就不会执行这个函数.这个该如何实现呢?如下: 1 def check(allow_users): 2 def inner_check(fn): 3 def wrap(username,*args,**kwargs): 4 '''This is wrap''' 5 if username in allow_users: 6 return fn(username,*args,**kwargs)

由浅入深,走进Python装饰器-----第五篇:进阶--类装饰类

**类装饰器** @类 类 4.1 用类装饰器来扩展原类( 增加属性和方法 ) # 用类装饰器来扩展原函数, 通过对象函数化触发__call__方法,进行返回 class KuoZhan(): def __call__(self,cls): return self.newfunc(cls) def good(self): print("新增的方法!") def newfunc(self,cls): def in_newfunc(): cls.addpty = "新增的属性&q

Python装饰器由浅入深

装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们以装饰函数为例子介绍其用法.要理解在Python中装饰器的原理,需要一步一步来.本文尽量描述得浅显易懂,从最基础的内容讲起. (注:以下使用Python3.5.1环境) 一.Python的函数相关基础 第一,必须强调的是python是从上往下顺序执行的,而且碰到函数的定义代码块是不会立即执行它的,只

【转】九步学习python装饰器

本篇日志来自:http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html 纯转,只字未改.只是为了学习一下装饰器.其实现在也是没有太看明白,对于装饰器我就是用的时候找例子,能蒙对,但是用过之后一段时间就忘了.还是用的少.有空应该好好看一看的,包括闭包.对于各种现代编程语言来说闭包都是很重要的.在这里先谢过原作者,如有侵权请告知. =-=-=-=-=-=-=-=-=-=-一条不怎么华丽的分隔线-=-=-=-=-=-=-=-=-=-= 这

[转载]Python装饰器学习(九步入门)

本文转载于: http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html 第一步:最简单的函数,准备附加额外功能 # -*- coding:gbk -*- '''示例1: 最简单的函数,表示调用了两次''' def myfunc(): print("myfunc() called.") myfunc() myfunc() 第二步:使用装饰函数在函数执行前和执行后分别附加额外功能 # -*- coding:gbk -*- ''

Python装饰器学习

Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 ? 1 2 3 4 5 6 7 8 # -*- coding:gbk -*- '''示例1: 最简单的函数,表示调用了两次''' def myfunc():     print("myfunc() called.") myfunc() myfunc() 第二步:使用装饰函数在函数执行前和执行后分别附加额外功能 ? 1 2 3 4 5 6

Day5 python装饰器

一.python装饰器基本概念 定义:本质是函数,用来装饰其他函数,即为其他函数添加附加功能. 原则:1.不能修改被装饰函数的源代码:    2.不能修改被装饰函数的调用方式. 实现装饰器的知识储备: 1.函数即"变量". 2.高阶函数 a.把一个 函数名 当作实参传给另一个函数: b.返回值中包含 函数名 . 3.嵌套函数 即在用def定义一个函数的函数体中再用def定义函数. 高阶函数 + 嵌套函数 => 装饰器 二.函数即"变量" 定义一个变量 1 x

由浅入深,走进Python装饰器-----第二篇:进阶--函数装饰函数

上一篇:由浅入深,走进Python装饰器-----第一篇:基础 装饰器的使用种类: # 第一种 @函数 被装饰函数 # 第二种 @函数 被装饰类 # 第三种 @类 被装饰类 # 第四种 @函数 被装饰函数 本篇介绍第一种 @函数 被装饰函数 1.1 对带参数的原函数进行修饰 # 默认将old函数的参数传给outer里面的第一层函数 def outer(f): def inner(var): print("1 我是outer函数,接收外部传进来的old :",f) print("

学习Python装饰器,看这一篇文章就够了

讲 Python 装饰器前,我想先举个例子,虽有点污,但跟装饰器这个话题很贴切. 谈装饰器前,还要先要明白一件事,Python 中的函数和 Java.C++不太一样,Python 中的函数可以像普通变量一样当做参数传递给另外一个函数,例如: 先来看一个简单例子,虽然实际代码可能比这复杂很多: 说到这里.顺便提醒下大家不管你是为了Python就业还是兴趣爱好,记住:项目开发经验永远是核心,如果你缺新项目练习或者没有python精讲教程,可以去小编的Python交流.裙 :七衣衣九七七巴而五(数字的