Python 如何理解又晕又好用的装饰器

Python 如何理解又晕又好用的装饰器

Python 装饰器这东西对初学者来说是个坑,很容易绕晕,笔者当时初学装饰器时花费了数天时间,看了不同讲师对这块内容的讲解,还是一知半解。  


 不过装饰器在开发中可是很好用的,有必要攻破,希望这篇文章能帮助学习者快速攻破难关。


初步理解

# 先来看一个简单函数

def show():
    print ('Mr tu')

show()

# 执行结果 :

Mr tu


# 现在我们用装饰器扩展这个函数,在打印 " Mr tu " 之前打印一行 " hello "  


def decorate(fun1):
    def wapper():
        print('hello')
        fun1()
    return wapper


@decorate
def show():
    print ('Mr tu')

show()


# 执行结果 :

hello
Mr tu


# 现在解释上面的代码。

# 1、首先 def decorate(fun1) 定义一个装饰器函数,在此函数里又定义了一个wapper子函数,子函数可以继承父函数的参数。

# 2、 @'函数名'是Python的一种语法糖 @decorate 等于 decorate(show) 

# 还是晕,不明白?  没关系,看下面代码:


def decorate(fun1):
    def wapper():
        print('hello')
        fun1()
    return wapper


def show():
    print ('Mr tu')

f1 = decorate(show)
f1()

# 执行结果 :

hello
Mr tu

# 换成这种写法,执行效果是一样的,因为这就是 @decorate 的本质。

# 就是将被装饰器装饰的函数show作为参数传给装饰器函数。

# 总结执行过程:

# 1、show函数作为参数传给装饰器函数 decorate ,那么 fun1 = show

# 2、这时执行到装饰器的子函数 wapper,子函数可以继承父函数的参数,所以可以调用 fun1 

# 3、然后wapper函数执行 print 打印一行 "hello" , 再然后  调用fun1() —— 这里其实就是执行了show函数。  因为在装饰器一开始执行的时候就把show函数作为参数赋值给了fun1.


# 现在明白了吧,只要这里明白,下面的就很好理解了。

装饰带参数的函数

# 一个参数

def decorate(fun1):
    def wapper(arg1):
        print('hello')
        fun1(arg1)
        print('nice to meet you')
    return wapper

@decorate
def show(arg1):
    print (arg1)

    
show('Mr Alice')

# 执行结果:

hello
Mr Alice
nice to meet you


# 两个参数

def decorate(fun1):
    def wapper(arg1,arg2):
        print('hello')
        fun1(arg1,arg2)
        print('nice to meet you')
    return wapper

@decorate
def show(arg1,arg2):
    print (arg1,arg2)


show('Mr Alice','Mr Tom')

# 执行结果:

hello
('Mr Alice', 'Mr Tom')
nice to meet you


# n个参数

def decorate(fun1):
    def wapper(*args,**kwargs):
        print('hello')
        fun1(*args,**kwargs)
        print('nice to meet you')
    return wapper

@decorate
def show(*args,**kwargs):
    print (args[0])
    print (args[1])
    print (args[2])


show('Mr Alice','Mr Tim','Mr tu')


# 执行结果:

hello
Mr Alice
Mr Tim
Mr tu
nice to meet you

一个函数被多个装饰器装饰

def decorate01(fun1):
    def wapper(*args,**kwargs):
        print('hello world')
        print('I am decorate01')
        fun1(*args,**kwargs)
    return wapper


def decorate02(fun1):
    def wapper(*args,**kwargs):
        print ('I am decorate02')
        fun1(*args,**kwargs)
        print('nice to meet you')
    return wapper


@decorate01
@decorate02
def show(*args,**kwargs):
    print (args[0])
    print (args[1])
    print (args[2])


show('Mr Alice','Mr Tim','Mr tu')


# 执行结果:

hello world
I am decorate01
I am decorate02
Mr Alice
Mr Tim
Mr tu
nice to meet you


# 观察print放置的位置不同,对应的输出结果不同。


def decorate01(fun1):
    def wapper(*args,**kwargs):
        print('hello world')
        fun1(*args,**kwargs)
        print('I am decorate01')  # 替换到了下面
    return wapper


def decorate02(fun1):
    def wapper(*args,**kwargs):
        print ('I am decorate02')
        fun1(*args,**kwargs)
        print('nice to meet you')
    return wapper


@decorate01
@decorate02
def show(*args,**kwargs):
    print (args[0])
    print (args[1])
    print (args[2])


show('Mr Alice','Mr Tim','Mr tu')


# 执行结果:

hello world
I am decorate02
Mr Alice
Mr Tim
Mr tu
nice to meet you
I am decorate01

装饰器功能扩展

#!/usr/local/python27/bin/python2.7

def before(request,*args,**kwargs):
    print('before')


def after(request,*args,**kwargs):
    print('after')


def Filter(before_func,after_func):
    def outer(fun1):
        def wapper(request,*args,**kwargs):

            before_result = before_func(request,*args,**kwargs)
            if(before_result != None):
                return before_result;


            fun1_result = fun1(request,*args,**kwargs)
            if(fun1_result != None):
                return fun1_result;


            after_result = after_func(request,*args,**kwargs)
            if(after_result != None):
                return after_result;

        return wapper
    return outer



@Filter(before,after)
def show(request,*args,**kwargs):
    print ('Mr tu')

    
show('1')


# 执行结果:

before
Mr tu
after

函数若未定义返回值,执行成功返回值默认为 None ,这里的语句 if (before_result != None) 意思就是before函数执行失败时采取什么操作。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/108895.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • FlashFXP v3.5.4注册码+FlashFXP v3.6.0注册码+FlashFXP v3.7.2.build.1266注册码[通俗易懂]

    FlashFXP v3.5.4注册码+FlashFXP v3.6.0注册码+FlashFXP v3.7.2.build.1266注册码[通俗易懂]FlashFXP是功能强大的FXP/FTP软件,融合了一些其他优秀FTP软件的优点,如像CuteFTP一样可以比较文件夹,支持彩色文字显示;像BpFTP支持多文件夹选择文件,能够缓存文件夹;像LeapFTP一样的外观界面,甚至设计思路也差相仿佛。支持文件夹(带子文件夹)的文件传送、删除;支持上传、下载及第三方文件续传;可以跳过指定的文件类型,只传送需要的文件;可以自定义不同

  • 解除80端口占用_443端口和80端口被占用

    解除80端口占用_443端口和80端口被占用有朋友问到,我本地phpnow,想使用80端口,但是每次都提示端口占用,有什么办法可以解决,那么最模板找出相关资料,提示如下:开始–运行–cmd进入命令提示符输入netstat-ano即可看到所有连接的PID之后在任务管理器中找到这个PID所对应的程序如果任务管理器中没有PID这一项,可以在任务管理器中选”查看”-“选择列”经常,我们在启动应用的时候发现系统需要的端口被别的程序占用,…

  • 双代号网络图与双代号时标网络图_双代号网络图和单代号网络图

    双代号网络图与双代号时标网络图_双代号网络图和单代号网络图一、双代号网络图1、压缩关键活动2、压缩可以压的活动3、压缩便宜的活动4、压缩后是否有优化二、双代号时标网络图1、关键途径:起点到终点没有波浪线的路径:ADH或12682、虚工作:是垂直

  • matlab导入文件夹里所有图片_如何创建快捷方式到指定文件夹

    matlab导入文件夹里所有图片_如何创建快捷方式到指定文件夹在matlab中,直接imwrite()保存图片,会保存到当前工作目录文件夹或其子文件夹。%直接保存imwrite(picture,’test1.png’)%在当前工作目录下新建文件夹并保存mkdirimage%如果文件夹已存在,会有警告,但不影响运行imwrite(picture,’image/test1.png’)如果要把图片保存到其他指定的文件夹,…

  • map遍历的几种方式分别是什么「建议收藏」

    map遍历的几种方式分别是什么「建议收藏」map遍历的方式有4种1、使用for循环遍历map;2、使用迭代遍历map;3、使用keySet迭代遍历map;4、使用entrySet遍历map。java代码:Map<string

  • 怎么用命令提示符运行JAVA代码_java命令提示符如何进入

    怎么用命令提示符运行JAVA代码_java命令提示符如何进入展开全部用命令提示符编译Java程序的方法62616964757a686964616fe59b9ee7ad9431333363363432我们先新建文本文档,输入自己的java程序。这里我写一个简单的java程序,来做示范。importjava.util.*;publicclassHelloDate{publicstaticvoidmain(String[]args){System….

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号