装饰器函数的构造

装饰器函数的构造

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

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

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

装饰器模板

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


相关推荐

  • 彻底搞懂Java多态

    彻底搞懂Java多态很多初学者在自学 Java 时候都卡在了 Java 多态 本教程从实际案例出发阐述 Java 多态现象及 Java 多态的原理 通过案例理解多态的现象需求描述多态是类在继承关系下的一种形态 下边先通过一个需求展示下多态的现象 攀博课堂是一个在线教育学习平台 有一个具体的功能需求 当学员登录后系统需要根据学员的类型获取他在攀博课堂的服务权限 比如 对于普通学生他可以自学 Java 课程 下载资源 在线问答交流 对于 Vip 学员还可以额外有专属老师指导 专属交流群等 Vip 服务 如何使用面向对象的编程思想实现这一功能需求

    2025年7月31日
    0
  • VSCode 断点调试项目「建议收藏」

    VSCode 断点调试项目「建议收藏」1.安装必须程序首页下载VSCode,打开一个项目扩展安装DebuggerforChrome插件用于Chrome调试;点击扩展搜索DebuggerforChrome然后点击安装2.VScode项目配置打开项目界面按F5出现界面选择Chrome添加成功后点击调试,添加配置,自动生成launch.json,添加配置的url为iis配置地址3…

    2022年5月21日
    38
  • modelsim-win64-10.4-se 下载、安装、破解全攻略(屡试不爽)

    modelsim-win64-10.4-se 下载、安装、破解全攻略(屡试不爽)本教程包括软件下载、破解文件下载、安装破解方法,助你一次成功。软件安装好了却不能用,想必大家都有过这样的痛苦和无奈。这款软件的破解花了我整整一个下午的时间,期间在网上找了各种方法尝试均以失败告终,差点让我放弃破解而着手去换操作系统。网上的方法多存在着疏漏和差错,所以这也是我写次教程的初衷,希望能帮到大家,少走弯路。本人使用系统声明:win864位专业版以及win1064位安装

    2022年5月24日
    160
  • 【知识普及】平板的屏幕分辨率和屏幕比例_和平精英平板分辨率

    【知识普及】平板的屏幕分辨率和屏幕比例_和平精英平板分辨率针对IOS,Android手机分辨率大小、屏幕尺寸、开发尺寸的参考。在实际页面的开发过程,往往显示屏幕的宽度换算为像素尺寸的1/2。IOS:6.5英寸——1242x2688px——XsMax6.1英寸——828x1792px——XR5.8英寸——1125x2436px——X/Xs5.5英寸——1242x2208px——6+…

    2022年8月13日
    2
  • VMware虚拟机安装WIN7操作系统

    VMware虚拟机安装WIN7操作系统

    2021年5月30日
    139
  • acwing1057. 股票买卖 IV(状态机模型)

    acwing1057. 股票买卖 IV(状态机模型)给定一个长度为 N 的数组,数组中的第 i 个数字表示一个给定股票在第 i 天的价格。设计一个算法来计算你所能获取的最大利润,你最多可以完成 k 笔交易。注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。一次买入卖出合为一笔交易。输入格式第一行包含整数 N 和 k,表示数组的长度以及你可以完成的最大交易数量。第二行包含 N 个不超过 10000 的正整数,表示完整的数组。输出格式输出一个整数,表示最大利润。数据范围1≤N≤105,1≤k≤100输入样例1:3 22

    2022年8月9日
    1

发表回复

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

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