装饰器函数的构造

装饰器函数的构造

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

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

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

装饰器模板

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)
上一篇 2021年11月11日 下午5:00
下一篇 2021年11月11日 下午5:00


相关推荐

  • 使用Diffie-Hellman算法(非对称加密算法)得到对称加密需要的秘钥

    使用Diffie-Hellman算法(非对称加密算法)得到对称加密需要的秘钥目录 0 摘要 1 概述 2 Diffie Hellman 算法原理 2 1Diffie Hellman 算法原理 2 2Diffie Hellman 算法的优缺点转载自原文在原文基础上优化了一下 加上注释 更好读懂 0 摘要非对称加密算法又称公开密钥加密算法 非对称加密是相对于对称加密而言的 对称加密指的是通信双方使用的密钥是一致的 而非对称加密就是算法使用的密钥不一致 非对称加密的好处是当通信双方没有事先协商密钥的情况下也能进行安全通信 而在互联网普及的今天 很多通信双方往往在事先是无法协商好密钥的

    2026年3月16日
    2
  • 在 Docker 中運行 OpenClaw:逐步部署指南

    在 Docker 中運行 OpenClaw:逐步部署指南

    2026年3月13日
    2
  • java一种集合_java创建集合

    java一种集合_java创建集合深入浅出学Java——HashMap哈希表(hashtable)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,本文会对java集合框架中的对应实现HashMap的实现原理进行讲解,然后会对JDK7的HashMap源码进行分析。一、什么是哈希表在讨论哈希表之前,我们先大概了解下其他数据结构在新增,…

    2025年10月23日
    4
  • ARM指令中LDR与MOV的区别与应用——看这一篇就够了

    ARM指令中LDR与MOV的区别与应用——看这一篇就够了ARM指令中LDR与MOV的区别与应用、从内存中寻址的方法、LDR伪指令和MOV指令的异同

    2022年6月17日
    31
  • 回溯算法 js_回溯算法代码

    回溯算法 js_回溯算法代码回溯算法是算法设计中的一种回溯算法是一种渐进式寻找并构建问题解决方式的策略回溯算法会先从一个可能的动作开始解决问题,如果不行,就回溯并选择另一个动作,直到将问题解决使用场景有很多路在这些路中,有死路和出路通常需要递归来模拟所有的路leetcode46:全排列解题思路要求:1所有排列情况;2没有重复元素有出路有死路使用回溯算法解题步骤用递归模拟出所有情况遇到包含重复元素的情况,就回溯收集所有到达递归终点的情况,并返回code//时间复杂度O.

    2022年10月4日
    5
  • TextCNN文本分类(keras实现)「建议收藏」

    TextCNN文本分类(keras实现)「建议收藏」目录前言:一、论文笔记二、Keras文本预处理1、读取数据集2、将文字转换成数字特征3、将每条文本转换为数字列表4、将每条文本设置为相同长度5、将每个词编码转换为词向量6、Keras文本预处理代码实现三、基于keras的TextCNN模型的构建、训练与测试1、基础版CNN(模仿LeNet-5)2、简单版TextCNN3、使用Word2Vec词向量…

    2022年6月28日
    34

发表回复

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

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