装饰器函数的构造

装饰器函数的构造

由于软件的设计遵循开发封闭原则(对于扩展开发,对于程序修改封闭)。所以对于软件的扩展是对软件二次开发的最好途径。这时候就需要使用到装饰器这个概念了。

装饰器就是为装饰的对象添加新的功能,并且是在不修改源码的情况下,还必须使得在外行看起来没有发生任何变化(调用方法、软件实现主要功能……)。

装饰器分为无参装饰器和有参装饰器,装饰器的实现都是通过“函数嵌套+闭包+函数对象”组合生成的。

装饰器模板

def outter(func):
	# 传进来的是被装饰的函数的对象
	def wrapper(*args,**kwargs):
		res = func(*args,**kwargs)
		return res
	return wrapper

@outter
def index(x,y):
	print(x,y)

无参装饰器的实现

import time

# 定义一个小函数
def index():
    time.sleeep(1.5)
    print("Welcome to index page!!!")
    return 100

index()            # 调用函数

如果需要在这个函数调用时候添加一个功能:就是实现输出调用函数需要使用的时间,虽然说这个功能实现很简单,并没有什么复杂的,但是如果只是使用下面的这种解法,那么就太老土了。
解法一:(老土、麻烦)

start = time.time()
index()            # 调用函数
print("用时:",time.time()-start)

这样子对于只是一个两个函数的时候,就能够简单实现,但是如果很多的函数调用都需要输出时间的时候就会很麻烦了,代码量也会变得很累赘了。

解法二:(调用方式改变了,不是很合要求)

def timer(fun):
    start = time.time()
    fun()            # 调用函数
    print("用时:",time.time()-start)
 
timer(index)         # 调用一个新的函数,实现所需要的功能

这个方法是对第一个方法的改进,减少了代码量,但是同时也带来了一个缺点,那就是改变了调用方式,这样子好像不太满足要求了。

解法三:(使用装饰器)

import time

def timer(func):
    def wrapper(): # 引用外部作用域的变量func
        start_time=time.time()
        res=func()
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    return wrapper
  
 # 定义一个小函数
@ timer                    # 添加装饰器对象
def index():
    time.sleeep(1.5)
    print("Welcome to index page!!!")
    return 100

# 这时候的调用方式
index()               # 调用函数,但是这时候调用的函数就不再是原先的index函数了,而是加了装饰器的index函数

使用装饰器之后,调用方式没有发生任何的改变,同时也实现了附加的功能;同时如果还有其他的函数想要实现这个种附加的功能也这需要添加一个装饰器就可以了。

有参装饰器的实现

由于语法糖 @ 的限制,outter函数只能有一个参数,并且这才是只用来接受被装饰对象的内存地址

# 定义一个验证功能的装饰器
def auth(driver):      # 最高层传递参数(第三层)
    def deco(func):
        def wrapper(*args,**kwargs):
            name = input("input user>>").strip()
            pwd = input("input pwd>>").strip()
            if driver == 'file':
                print("基于文件验证")
                # 编写基于文件的认证,认证通过则执行res=func(*args,**kwargs),并返回res
                
                # 打开文件,传文件中读取用户信息进行匹配
                if name == "xiaoming" and pwd == "123456":
                    print("基于文件验证成功")
                else:
                    print("基于文件验证失败")

            elif driver == 'mysql':
                # 编写基于mysql认证,认证通过则执行res=func(*args,**kwargs),并返回res
                print("基于数据库验证")
                if name == "xiaoming" and pwd == "123456":
                    print("基于数据库验证成功")
                else:
                    print("基于数据库验证失败")

            else:
                print("传入验证参数有误")
        return wrapper
    return deco


# auth(driver="file") ----- 运行之后返回一个deco函数的内存地址;(添加这一层闭包的主要功能就是为了传递参数)
# @deco 这个就是一般的装饰器语法糖(一个两层的闭包函数)
@auth(driver="file")
def index(x,y):
    print("index{}{}".format(x,y))


@auth(driver="mysql")
def home(x,y):
    print("index{}{}".format(x,y))


index(2,6)

home(5,9)

综合以上操作就实现了有参装饰器的传递,但是还存在一个问题,就是虽然有参装饰器是实现了,并且调用方式都没发生任何的变化,但是还有一个问题,那就是函数的属性以及一些其他的附加内容,并没有进行修改,这时候其实需要把他们全部进行修改才是一个完美的装饰器。

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

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/115127.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • HSQL 学习笔记

    HSQL 学习笔记HSQL学习笔记1.    hsql 学习1.1.    学习目的本文档是针对hSQL 数据库方面的基础学习,为了使项目组成员能够达到使用hSQL 数据库的目的。1.2.    培训对象开发人员1.3.    常用词及符号说明常用词:hsql:一种免费的跨平台的数据库系统E:\hsqldb:表示是在dos 命令窗口下面1.4.    参考信息doc

    2022年9月22日
    5
  • ideaJ 2021 mac 激活码(最新序列号破解)

    ideaJ 2021 mac 激活码(最新序列号破解),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月19日
    47
  • jmeter登录返回数据给下一个接口_mysql读写分离实现

    jmeter登录返回数据给下一个接口_mysql读写分离实现问题描述场景是这样的,我们的支付系统在一笔支付完成后,需要发出通知给到商户。支付完成的消息通过消息队列发送给通知的服务。通知服务的有一部分处理逻辑是这样的:notifyPersist.saveNotifyRecord(notifyRecord);notifyRecord=rpNotifyService.getNotifyByMerchant…

    2022年10月13日
    3
  • macbook下载的安装包怎么安装_mac安装软件拉进application

    macbook下载的安装包怎么安装_mac安装软件拉进applicationMac下面除了用dmg、pkg来安装软件外,比较方便的还有用MacPorts来帮助你安装其他应用程序,跟BSD中的ports道理一样。MacPorts就像apt-get、yum一样,可以快速安装些软件。下面将MacPorts的安装和使用方法记录在这里以备查。访问官方网站http://www.macports.org/install.php,这里提供有dmg安装和源码安装两种方式,d

    2022年9月21日
    3
  • HTML期末大作业~餐饮文化学生网页设计作业(HTML+CSS+JavaScript)[通俗易懂]

    HTML期末大作业~餐饮文化学生网页设计作业(HTML+CSS+JavaScript)[通俗易懂]HTML期末大作业~基于HTML+CSS+JavaScript饮食网站设计与实现关于HTML期末网页制作,大作业A+水平~饮食网页作业HTML+CSS+JavaScript实现,共有联系我们在线留言资质荣誉行业资讯成功案例新闻资讯产品中心发展历史关于我们8个页面!原始HTML+CSS+JS页面设计,可以学习学习,大学网页设计作业,~这是一个不错的网页制作,画面精明,非常适合初学者学习使用。作品演示1.关于我们2.产品中心3.新闻资讯4.资质荣誉5.在线留言6.

    2025年10月2日
    2
  • 物联网智能家居系统设计方案(想开一家智能产品店)

    物联网智能家居系统1.需求分析、原理/基础准备1.1实验目的1.2基本功能1.3模块功能描述1.3.1主功能函数模块1.3.2串口通信模块1.3.3电机模块1.3.4时间获取模块1.3.5温湿度光电模块1.3.6烟雾模块1.3.7PWM调光模块1.3.8灯泡模块2.概要设计说明2.1模块调用图3.详细设计说明(各部分成员分工部分)3.1主程序模块3.2通信模块3.3串口模块3.4PWM调光模…

    2022年4月12日
    29

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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