首页 > 编程语言 >Python中的装饰器

Python中的装饰器

时间:2022-10-10 14:58:19浏览次数:51  
标签:__ Python args def func 装饰 decorator

 

0 前言

千言万语抵不过一句话:“Matlab 中可以使用 Python.”

今天修改代码过程中遇到装饰器语法,顺便总结一下以方便以后查看,也分享给大家,希望有帮助吧。

装饰器(Decorator)也称为包装器(Wrapper),也叫装饰者模式(设计模式的一种)。

《设计模式》一书中是这样描述装饰者模式的:

动态地给一个对象添加一些额外的职责,就增加功能来说,装饰者模式相比生成子类更为灵活。

Python 中提供了装饰器的语法糖,使用起来非常方便。下面进行详细介绍。

1 预备

所谓装饰器可以理解为把一个对象通过装饰变成“另一个”对象,这个“另一个“对象还是它本身,期间内部状态会发生改变。一个简单的例子:新房 = 装饰器(毛坯房)。毛坯房经过装饰最终变成了新房,但它还是房子!在毛坯房变成新房的这个过程中,会由装饰器执行一些具体的工作,比如粉刷墙、安装家具等,从外界看上去它是一个被装饰的新房子对象,但实际上仍然是一个房子对象(毛坯房,新房都是房子对象)。

回归到万物皆对象的 Python 中,装饰器的本质就是将一个函数对象作为参数传递给另一个函数返回被装饰函数的对象,即

func = decorator(func)

其中decorator称为装饰器函数,func称为需要被装饰的函数对象。比如我们登录一个系统时首先会验证用户名和密码是否正确,验证通过后会准许登入系统。那么装饰器的职责就是专门负责验证用户名和密码是否正确,一个系统如果被这样的装饰器装饰后,那它就具备了登录验证的额外功能。用代码可表示为:

def decorator(func):

    def _decorator(*args):
        name, password = True, True
        if name and password:
            print('verify successfully')
            func(*args)
            print('login successfully')
        else:
            # Do something
            pass

    return _decorator

需要装饰的函数代码如下:

def func(arg1='Study', arg2='System'):
    print('Welcome ' + arg1 + ' ' + arg2 + '!')

一个调用装饰器的脚本看上去是这样的:

>>> func = decorator(func)
>>> print(func.__name__)
_decorator

>>> func()
verify successfully
Welcome Study System!
login successfully

上面第1行代码表示装饰的整个过程,而产生的函数对象func却指向了decorator的局部函数_decorator,与我们期待的func不一样,它重写了函数的名字和注释文档,幸运的是Python提供了一个简单的函数来解决这个问题,即functools.wraps。另外,语句func = decorator(func)可以由语法糖:@decorator来代替。修改上述代码后为:

from functools import wraps

def decorator(func):
    
    @wraps(func)
    def _decorator(*args):
        name, password = True, True
        if name and password:
            print('verify successfully')
            func(*args)
            print('login successfully')
        else:
            # Do something
            pass

    return _decorator


@decorator
def func(arg1='Study', arg2='System'):
    print('Welcome ' + arg1 + ' ' + arg2 + '!')

    
>>> print(func.__name__)
func

>>> func()
verify successfully
Welcome Study System!
login successfully

现在来看,达到了我们预期的结果。

2 不带和带参数的装饰器

编写自定义装饰器有很多方法,但最简单和最容易理解的方法是编写一个函数,返回封装原始函数调用的一个子函数。

不带参数模式:

from functools import wraps

def mydecorator(func):
    
    @wraps(func)
    def _mydecorator(*args, **kwargs):
        # 在调用实际函数之前做些填充工作
        res = func(*args, **kwargs)
        # 做完某些填充工作之后
        return res
    
    return _mydecorator  # 返回子函数

当装饰器需要传入参数时必须使用第二级封装

带参数模式

from functools import wraps

def mydecorator(arg1, arg2):
    
    def _mydecorator(func):
        @wraps(func)
        def __mydecorator(*args, **kwargs):
            # 在调用实际函数之前做些填充工作
            res = func(*args, **kwargs)
            # 做完某些填充工作之后
            return res
        
        return __mydecorator
    
    return _mydecorator  # 返回子函数

3 使用类实现装饰器

一个实例对象在默认情况下不可调用,只有实现了__call__方法后才能调用。

下面介绍用类实现不带和带参数的装饰器

from functools import wraps


# 无参数形式 (第1种方法) 
class CheckLogin:
    
    def __init__(self, func):
        self.f = func
        
    def __call__(self, *args, **kwargs):
        print('*************')
        print('登录验证')
        self.f(*args, **kwargs)


# 无参数形式 (第2种方法)      
class CheckLogin:
    
    def __call__(self, func):
        @wraps(func)
        def _mydecorator(*args, **kwargs):
            # Do something
            return func(*args, **kwargs)
        
        return _mydecorator
# 注意装饰时需要用@CheckLogin()后边一定要带上括号


# 有参数形式
class CheckLogin:
    
    def __init__(self, arg=None):
        self.arg = arg
    
    def __call__(self, func):
        @wraps(func)
        def _mydecorator(*args, **kwargs):
            # Do something
            return func(*args, **kwargs)
        
        return _mydecorator
# 装饰:
@CheckLogin(arg)

使用类实现不带参数装饰器时,有两种方法,需要注意的是第2种方式需要加上()。

4 结语

总结了 Python 的装饰器用法,函数通过嵌套子函数创建装饰器,而类通过重写__call__方法实现装饰器。在创建带参数的装饰器时,通过类来创建会更优雅和方便。

以上


5 参考文献

https://www.runoob.com/w3cnote/python-func-decorators.html

http://c.biancheng.net/design_pattern/

标签:__,Python,args,def,func,装饰,decorator
From: https://www.cnblogs.com/qpwz/p/16775680.html

相关文章

  • [MicroPython ESP32] 内存分析
    [MicroPythonESP32]内存分析[(1)芯片:ESP32-WROOM-DA]手册:https://www.espressif.com.cn/zh-hans/support/documents/technical-documents?keys=&field_type_tid%5B%5D......
  • 怎么安装python?
    1.先在命令行输入python查看是否已经安装。2.开始下载python,然后安装  3.安装完成之后在命令行输入python看是否安装成功了,输入wherepython能查看安装在哪个路径,也......
  • python重拾第七天-面向对象进阶
    本节内容:面向对象高级语法部分经典类vs新式类静态方法、类方法、属性方法类的特殊方法反射异常处理Socket开发基础作业:开发一个支持多用户在线的FTP程序......
  • Python爬虫抓取数据时怎么防止ip被封
    大数据公司在做数据分析的时候,对目标网站频繁访问很容易触发网站的反爬机制,因此如果想要突破限制只能使用动态ip频繁切换地址模拟真实客户访问网站才能起到防封效果。比如在......
  • 记一次win10 python -m http.server 启动后无法访问的经历
    前言最近需要在win10上使用python创建一个http文件服务(默认端口8000),结果执行了python3-mhttp.server-b0.0.0.0后,发现服务跑起来了,但浏览器无法访问http://loc......
  • 【Python秒杀脚本】淘宝或京东等秒杀抢购
    我们的目标是秒杀淘宝或京东等的订单,这里面有几个关键点,首先需要登录淘宝或京东,其次你需要准备好订单,最后要在指定时间快速提交订单。 这里就要用到一个爬虫利器Seleniu......
  • python将print的数据输出到txt文件中
    前言:在写一些小的测试脚本时,需要查看一些日志,我们不会去搭建一个logger工具;而是选择直接输出到txt文件中,测试完后,也方便查看结果。在需要输出打印前面,打开txt文件,以追加的......
  • 37、linux下安装python3.6和django
    37.1、安装python:1、python介绍:python是一种面向对象的,解释型的计算机语言,它的特点是语法简介,优雅,简单易学。1989年诞生,Guido(龟叔)开发。编译型语言:代码在编译之后,编译成......
  • pip3 install requests Cannot open D:\Python35\Scripts\pip3-script.py
    1、问题描述:使用pip(或pip3)指令安装模块时,出现了CannotopenD:\Python35\Scripts\pip3-script.py的报错信息2、原因分析:pip安装出错3、解决方式:可以使用这条指令来......
  • window 配置 python 环境命令
    npminstall安装依赖的时候,报python的错误先安装cnpmnpminstall-gcnpm--registry=https://registry.npm.taobao.orgnpminstall--global--productionwin......