栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Python 装饰器的用法 一篇细讲(初学角度入手)

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python 装饰器的用法 一篇细讲(初学角度入手)

2021.10.15 1.前话
  1. 因为我也是初学装饰器,所以可以较白话地讲它。
  2. 为什么突然学python装饰器?

发现代码可以更简洁,减少重复代码和重复工作,便于维护。

  1. 具体场景:

在写网站的时候,许多视图函数需要做是否登录判断或者是否允许操作判断,这样每个视图函数前面都要重复一遍代码,到后期,维护是个大问题:需要找到所有函数,一个个修改。

2.Python 装饰器
  1. 一个类似的场景,比如:我希望在下面这个函数的前面输出before,后面输出after。
def func():
    print('我是func函数')
    value = (1,2,3,)
    return value

res = func()
print(res)
  1. 如果只是一两个函数,我们完全可以这样
def func():
    print('before')
    print('我是func函数')
    print('after')
   	value = (1,2,3,)
    return value

func()
  1. 但如果是几十个几百个函数,哪天告诉你,我想改成前面after,后面before,或者说我不这么做了,就得在这几十个几百个函数中,改啊改。
  2. 但如果使用装饰器,就减少了大量的重复工作和工作量。
  3. 装饰器原理:

outer函数return inner,也就是说func = outer(func),即func=inner。

当执行func()的时候,即执行inner()。

inner里执行origin(),在inner里找不到origin,往上一层找,即outer,找到origin,origin即前面传过来的参数func,所以依然还是执行func(),执行origin()即执行func()。func函数有返回值,return res。

def outer(origin):
    def inner():
    	res = origin()
    	return res
    return inner

def func():
    print('我是func函数')
    value = (1,2,3,)
    return value

func = outer(func)

res = func()
print(res)
  1. 就上面的问题,也是在函数前和函数后加输出。
def outer(origin):
    def inner():
        print('before')
        res = origin()
        print('after')
        return res
    return inner

执行结果如下:

是不是感觉结果一样,还更麻烦了?
这就是前面说的,如果量少可以直接在函数里,前后加输出。
量大再用装饰器。

  1. 上面是原理,接下来才是python中装饰器的真正用法。

@装饰器函数名
def 函数():

再func上一行加@outer 相当于 func=outer(func)
(注意:装饰器的函数要放在使用装饰器的函数之前。)

@outer
def func():
    print('我是func函数')
    value = (1,2,3,)
    return value

res = func()
print(res)
  1. 如果现在有三个函数需要在前面和后面加输出,我只需要这些函数前,加上一个@outer,就完成了,而不是在每个函数里加两个print。可以想象一下不止三个,而是一百个函数。(当然是在有统一需求的时候更适用。)
def outer(origin):
    def inner():
        print('before')
        res = origin()
        print('after')
        return res
    return inner

@outer
def func():
    print('我是func函数')
    value = (1,2,3,)
    return value

@outer
def func2():
    print('我是func2函数')
    value = (1,2,3,)
    return value

@outer
def func3():
    print('我是func3函数')
    value = (1,2,3,)
    return value

res = func()
res1 = func2()
res2 = func3()

输入结果:

  1. 带n个参数的装饰器

上面讲的都是不带传参的函数,接下来讲带参数的。
假如,现在func有一个参数,func2有两个,func3有一个或者多个。

如果只在func函数中加入参数。
那么会报参数错误。

因为现在不仅仅是func函数的问题了,func = outer(func),现在的func = inner(),现在写的inner()没有接收参数,所以得补上,为了能接收不定个数的参数,我们用*args,**kwargs接收。

def outer(origin):
    def inner(*args, **kwargs):
        print('before')
        res = origin(*args, **kwargs)
        print('after')
        return res
    return inner

inner加了接收参数,但是最终还是执行的origin(),即func(),参数也不能少。
(这边inner是接收参数,origin是传参数)

3.总结

4.补充:扩展
def outer(origin):
    def inner(*args, **kwargs):
        '''inner文档注释'''
        print('before')
        res = origin(*args, **kwargs)
        print('after')
        return res
    return inner


@outer
def func(a1):
    '''func的文档注释'''
    print('我是func函数')
    value = (1,2,3,)
    return value

@outer
def func2(a1,a2):
    '''func2的文档注释'''
    print('我是func2函数')
    value = (1,2,3,)
    return value

print(func.__name__)
print(func.__doc__)
print(func2.__name__)
print(func2.__doc__)

__name__是获取函数名
__doc__是获取函数文档注释

输出结果:

都是inner的函数名和文档注释。
如果希望是原来函数的函数名和注释的话,需要引入functools
在inner函数前加个@functools.wrap(传过来的函数名)。

import functools

def outer(origin):
    @functools.wraps(origin)  # inner.__name__=origin.__name__
    def inner(*args, **kwargs):
        '''inner文档注释'''
        print('before')
        res = origin(*args, **kwargs)
        print('after')
        return res
    return inner

输出结果:

希望对初学装饰器的你有帮助。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/326064.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号