装饰器函数的构造

装饰器函数的构造

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

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

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

装饰器模板

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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Idea 删除当前一行的快捷键

    Idea 删除当前一行的快捷键使用eclipse,有时候出现多个空行时,习惯使用快捷键:Ctrl+D,删除当前一行。最近使用idea开发,发现手动删除空行,很麻烦,特意查了一下,发现是快捷键:Ctrl+Y。如下图所示:使用Ctrl+Y后删除当前行另外:可以使用设置,讲idea的快捷键设置为eclipse模式…

    2025年9月28日
    6
  • 第十八篇 项目范围管理__六个过程[通俗易懂]

    第十八篇 项目范围管理__六个过程[通俗易懂]项目范围管理包括以下过程

    2022年9月22日
    4
  • 用js来实现那些数据结构01(数组篇01-数组的增删)

    在开始正式的内容之前,不得不说说js中的数据类型和数据结构,以及一些比较容易让人混淆的概念。那么为什么要从数组说起?数组在js中是最常见的内存数据结构,数组数据结构在js中拥有很多的方法,很多初学者记

    2022年3月25日
    57
  • 2020vue面试题及答案_人际关系面试题及答案

    2020vue面试题及答案_人际关系面试题及答案1、虚拟DOM中key的作用:key是虚拟DOM对象的标识,当状态中的数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】的差异比较,比较规则如下:2、key的对比规则:1、旧虚拟DOM中找到了与新虚拟DOM相同的key:若虚拟DOM中内容没变,直接使用之前的真实DOM若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM………

    2025年8月31日
    6
  • C++ ^按位异或运算符

    C++ ^按位异或运算符参与运算的两个值,如果两个相应位相同,则结果为0,否则为1。即:0^0=0,1^0=1,0^1=1,1^1=0

    2022年5月12日
    40
  • (一)easyUI之第一个demo

    (一)easyUI之第一个demo一、下载官网下载:http://www.jeasyui.net/download/同时并下载官方中文API文档。解压后的目录结构:二、第一个demo1新建工程并导入包1新建工程并导

    2022年7月2日
    26

发表回复

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

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