首页 > 编程语言 >python装饰器

python装饰器

时间:2024-03-14 11:25:43浏览次数:22  
标签:python ---- time print login 装饰 def

一:什么是装饰器
器:指的是工具,可以定义为函数

装饰:指的是为其他事物添加额外的东西点缀

装饰器:指的是定义一个函数,该函数是用来给其他函数添加额外的功能

二、为什么要用装饰器
开放封闭原则:

开放:指的是对拓展功能是开放的

封闭:指的是对修改源代码是封闭的

对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着对象一旦设计完成,就可以独立完成其工作,而不要对其进行修改。

装饰器就是在不修改被装饰对象源代码以及调用方式的前提下为被装饰对象添加新功能。

三、装饰器的实现
函数装饰器分为:无参装饰器和有参装饰两种,二者的实现原理一样,都是’函数嵌套+闭包+函数对象’的组合使用的产物。

3.1:无参装饰器的实现
无参装饰器的模版

def outer(func):
    def wrapper():
        res = func()
        return res
    return wrapper
 
@outer    # 加在被装饰对象的上方

 



@outer # 加在被装饰对象的上方
如果想为下述函数添加统计其执行时间的功能

import time
def get_time():
    time.sleep(3)
    print("welcome")
    return 200
get_time()

 


使用装饰器:

import time
 
def outer(func):
    def wrapper():
        stat_time = time.time()
        res = func()
        end_time = time.time()
        print(f'程序运行的时间为{end_time-stat_time}')
        return res
    return wrapper
 
@outer
def get_time():
    time.sleep(3)
    print("welcome")
    return 200
 
get_time()

 


输出结果:

welcome
程序运行的时间为3.0009207725524902
3.2:有参装饰器的实现
有参装饰器的模版

def outer(func):
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        return res
    return wrapper
 
@outer 

 



@outer # 加在被装饰对象的上方
如果想为下述函数添加统计其执行时间的功能

import time
 
def time_demo(a, b):
    time.sleep(3)
    print("welcome")
    print(a+b)
 
time_demo(3, 5)

 


使用装饰器:

import time
 
def outer(func):
    def wrapper(a, b):
        stat_time = time.time()
        res = func(a, b)
        end_time = time.time()
        print(f'程序运行的时间为{end_time-stat_time}')
        return res
    return wrapper
 
@outer
def time_demo(a, b):
    time.sleep(3)
    print("welcome")
    print(a+b)
 
time_demo(3, 5)

 


输出结果:

welcome
8
程序运行的时间为3.0009207725524902
3.3:装饰器函数本身带有参数

@logging(level='INFO')它就是一个函数,会被立刻执行,返回结果是一个装饰器。

与上面的例子相同:

import time
 
def loglevel(level):
    def outer(func):
        def wrapper(a, b):
            stat_time = time.time()
            res = func(a, b)
            end_time = time.time()
            print(f'程序运行的时间为{end_time-stat_time}')
            if level == 'INFO':
                print("level is INFO")
            return res
        return wrapper
    return outer
 
@loglevel(level='INFO')    # 相当于:time_demo=loglevel("INFO")(time_demo), -> loglevel("INFO") = outer, 因此time_demo=outer(time_demo)
def time_demo(a, b):
    time.sleep(3)
    print("welcome")
    print(a+b)
 
time_demo(3, 5)

 


@loglevel(level='INFO'):先执行loglevel(level='INFO'),得到outer返回值后,再执行@outer

输出结果:

welcome
8
程序运行的时间为3.0051047801971436
level is INFO
3.4:叠加多个装饰器

@deco3
@deco2
@deco1
def index():
    pass

 


执行顺序是:从最上面的装饰器依次往下执行,将下面的作为参数传入

index=deco3(deco2(deco1(index)))

 

 

 

装饰器

 

def home():
    print("---首页----")
def america():
    print("----欧美专区----")
def japan():
    print("----日韩专区----")
def henan():
    print("----河南专区----")

 

假设这是一个网站的各个专区的页面,调用函数即为打开页面,现在要添加一个用户认证的功能

account = {
    "is_authenticated":False,# 用户登录了就把这个改成True
    "username":"alex", # 假装这是DB里存的用户信息
    "password":"abc123" # 假装这是DB里存的用户信息
}
def login():
    if account["is_authenticated"] is False:
        username = input("user:")
        password = input("pasword:")
        if username == account["username"] and password == account["password"]:
            print("welcome login....")
            account["is_authenticated"] = True
        else:
            print("wrong username or password!")
    else:
        print("用户已登录,验证通过...")


def home():
    print("---首页----")
def america():
    login()  # 执行前加上验证
    print("----欧美专区----")
def japan():
    print("----日韩专区----")
def henan():
    login()  # 执行前加上验证
    print("----河南专区----")
home()
america()
henan()

你可以加一个关于用户认证的函数,然后在每一个页面打开前都调用这个函数。

但是这样虽然程序的功能实现了,但是违反了“开放-封闭”原则。

  • 封闭:已实现的功能代码块不应该被修改

  • 开放:对现有功能的扩展开放

这样修改代码相当于是对已有的功能的代码块进行了修改,是不符合开放封闭原则的,所以要找一种不修改原来代码的方式来增加这个功能。

 

account = {
    "is_authenticated":False,# 用户登录了就把这个改成True
    "username":"alex", # 假装这是DB里存的用户信息
    "password":"abc123" # 假装这是DB里存的用户信息
}
def login(func):
    if account["is_authenticated"] is False:
        username = input("user:")
        password = input("pasword:")
        if username == account["username"] and password == account["password"]:
            print("welcome login....")
            account["is_authenticated"] = True
        else:
            print("wrong username or password!")
    if account["is_authenticated"] is True:  # 主要改了这
        func() # 认证成功了就执行传入进来的函数

def home(): print("---首页----") def america(): print("----欧美专区----") def japan(): print("----日韩专区----") def henan(): print("----河南专区----")

home() login(america) # 需要验证就调用 login,把需要验证的功能 当做一个参数传给login login(henan)

 

通过之前学过的高阶函数,在不修改源代码的情况下,实现了认证功能的添加,但是这种方式仍然不好,因为修改了原来程序的调用方式,修改以后,所有的用户都要修改调用方式,显然是不合理的。

那么如何在不修改源代码和原来调用方式的情况下给函数添加功能?

account = {
    "is_authenticated":False,# 用户登录了就把这个改成True
    "username":"alex", # 假装这是DB里存的用户信息
    "password":"abc123" # 假装这是DB里存的用户信息
}
def login(func):
    def inner(): # 再定义一层函数
        if account["is_authenticated"] is False:
            username = input("user:")
            password = input("pasword:")
            if username == account["username"] and password == account["password"]:
                print("welcome login....")
                account["is_authenticated"] = True
            else:
                print("wrong username or password!")
        if account["is_authenticated"] is True:
            func()
    return inner  # 注意这里只返回inner的内存地址,不执行

 


america()  # 相当于执行inner()
henan()

上面的代码将原函数名america传给login()函数,login()函又定义了一层函数inner,并且返回了内部函数的函数名inner,然后用america进行函数名的替换,这样再次执行america()时,相当于执行的就是

inner()函数。这样就实现了在没有修改源代码和调用方式的情况下给原函数增加功能的目的。

def america():
    print("----欧美专区----")
def henan():
    print("----河南专区----")
home()
america = login(america) 
henan = login(henan) 

# 通常装饰器使用这种写法

@login  # 相当于america = login(america)
def america():
    print("----欧美专区----")

@login  # 相当于henan = login(henan)
def henan():
    print("----河南专区----")

当需要给原函数传递参数时,可以使用非固定参数,即给innder(*args,**kwargs),然后给func(*args,**kwargs) 就可以实现了。

  1. #装饰器函数在被装饰函数定义好后立即执行。多个装饰器的调用顺序是自下往上的。
  2. # 被装饰函数执行时,装饰器的执行顺序是从上往下的。

 

 执行顺序如上。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_48323589/article/details/130189887

标签:python,----,time,print,login,装饰,def
From: https://www.cnblogs.com/sxy-blog/p/18072432

相关文章

  • Python的垃圾回收机制
    什么是垃圾回收机制垃圾回收(GarbageCollection)是一种自动内存管理机制,用于检测和释放不再被程序使用的内存资源,以避免内存泄漏和资源浪费。 在编程中,当对象被创建时,系统为其分配一块内存空间。但是,当对象不再被程序使用时,如果没有及时释放相关的内存空间,就会导致内存泄漏。垃......
  • Python特征选择技术总结
    本文还可以帮助你解答以下的面试问题:什么是特征选择?说出特性选择的一些好处你知道哪些特征选择技巧?区分单变量、双变量和多变量分析。我们能用PCA来进行特征选择吗?前向特征选择和后向特征选择的区别是什么?什么是特征选择,为什么它很重要?特性选择是选择与ML模型......
  • 使用Python检测贝叶斯网络的因果关系检测
    在机器学任务中,确定变量间的因果关系(causality)可能是一个具有挑战性的步骤,但它对于建模工作非常重要。本文将总结有关贝叶斯概率(Bayesianprobabilistic)因果模型(causalmodels)的概念,然后提供一个Python实践教程,演示如何使用贝叶斯结构学习来检测因果关系。背景在许多领域,......
  • 使用Python检测贝叶斯网络的因果关系检测
    在机器学任务中,确定变量间的因果关系(causality)可能是一个具有挑战性的步骤,但它对于建模工作非常重要。本文将总结有关贝叶斯概率(Bayesianprobabilistic)因果模型(causalmodels)的概念,然后提供一个Python实践教程,演示如何使用贝叶斯结构学习来检测因果关系。背景在许多领域,......
  • Python特征选择技术总结
    本文还可以帮助你解答以下的面试问题:什么是特征选择?说出特性选择的一些好处你知道哪些特征选择技巧?区分单变量、双变量和多变量分析。我们能用PCA来进行特征选择吗?前向特征选择和后向特征选择的区别是什么?什么是特征选择,为什么它很重要?特性选择是选择与ML模型......
  • python基于flask房产中介房屋供求系统django毕业设计项目lw附源码
    本设计要设计一个简单的网页,在研究的过程中具体有以下5个步骤:下面简要分析房产中介系统的业务:(1)注册、登录:注册普通账号登录。(2)用户个人信息修改:登录后可以修改用户的基本信息,也可以退出。(3)用户留言管理:用户填写留言的主题、联系人、电话、邮箱、留言内容。 (4)房屋......
  • 蓝桥杯Python国赛F题123(过70%代码)
    分析:明显考虑二分,(部分丑陋的笔记在下面,方便我自己看的,不喜勿喷)首先我们可以二分出包含在 [L,R]之间的完整的取值区间,[Get(a-1),Get(b)]因为左端点二分的是区间前端点,就是前端要包含在内,所以a-1然后就是对于两边突出部分进行计算,不知道为什么30%没有过,希望评论区......
  • PYTHON openpyxl 读取课程表,轮值排班表,输出每日班级简报
    源文件excel及python源文件链接:https://pan.baidu.com/s/1uswO_33jrgE3nvaJv47wGw提取码:clnw#frompickleimportAPPENDimportopenpyxlimportdatetimefromtimeimportstrftime#importre#fromdatetimeimportdatetime#fromdateutil.parserimportparse#impor......
  • Python实战:元组一次性数据的处理利器
    Python元组是一种不可变的序列类型,非常适合用于存储不应该被修改的数据。本文将深入探讨Python元组在处理一次性数据方面的优势和应用场景,包括元组的定义、操作、函数和方法,以及如何利用元组提高代码的可读性和性能。1.Python元组简介Python元组(tuple)是一种内置的数据类......
  • Python实战:Python集合的常见操作
    Python集合(set)是一种无序且元素唯一的容器,它是Python中一种基本的数据结构。本文将详细介绍Python集合的常见操作,包括创建集合、添加和删除元素、集合运算、集合推导式等。1.创建集合Python集合可以通过多种方式创建,包括直接赋值、使用内置函数set()和集合推导式等。示......