首页 > 编程语言 >Python基础之装饰器

Python基础之装饰器

时间:2023-05-31 17:22:59浏览次数:35  
标签:index 函数 Python 基础 time print login 装饰 def

装饰器

1、为什么要用装饰器

1.1、为程序提供扩展功能的可能性

1.2、要遵循开放封闭原则

1.3、禁止修改原代码,但是可以新增功能

1.4、也不能修改调用方式

2、什么是装饰器

2.1为被装饰对象添加新功能的工具

2.2、不修改被装饰对象源代码和调用方式

3、装饰器的核心思想

3.1、就是在"不改变被装饰对象"内部的代码和"原有调用方式"的基础之上再"添加额外的功能"

4、装饰器的实现

实现原理:
	函数嵌套+闭包+函数对象
    

简易版本的装饰器

########################################################### 
# 背景知识
def index():
    print("from index")
index()
# 现在让你统计index函数执行完毕之后的执行时间

# 时间模块
import time  # 内置模块,可以直接拿来使用

def index():
    time.sleep(3)
    print('from index')
# 1. 在函数执行之前打印一个时间点
start_time = time.time()
index()

# 2. 在函数执行完毕之后在打印一个时间点
end_time = time.time()

# 3. 两者的差就是函数的执行时间
print("index函数一共执行了:%s秒" % (end_time - start_time))
这样一个最low逼的装饰器就做好了

# 这样的装饰器可不可以用?
	可以用但是写死了,其他的函数想用就用不了,所以我们基于上方的前提上还可以再改改
    ###########################################################
 import time
def index():
    time.sleep(6)
    print('from index')


def outer(func):
    def get_time():
        start_time = time.time()
        func()
        end_time = time.time()
        print('函数执行了%s秒' % (end_time - start_time))
    return get_time


index=outer(index)
index()

# 这样的话这个装饰器就可以实现让多个函数使用的,也不会有代码冗余问题

解决参数问题

至此我们便实现了一个无参装饰器timer,可以在不修改被装饰对象index源代码和调用方式的前提下为其加上新功能。但我们忽略了若被装饰的函数是一个有参函数,便会抛出异常。因为调用的那个index使我们自己给get_time内存地址起的一个名字,而不是我们定义的那个函数index,所以就会出现报错,针对问题我们又该如何解决呢?
import time


def index(username, name):
    time.sleep(3)
    print('from index')


def outer(func):
    def get_time(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print('函数执行了%s秒' % (end_time - start_time))

    return get_time


index = outer(index)
index('tony', 'kevin')

函数的返回值问题

import time


def index():
    time.sleep(3)
    print('from index')


def home():
    time.sleep(6)
    print('from home')


def outer(func):
    def get_time(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)
        end_time = time.time()
        print('函数执行了%s秒' % (end_time - start_time))
        return res

    return get_time


index = outer(index)
res1 = index
res1()

home = outer(home)
res2 = home
res2()

# 谁调用outer谁就拿get_time返回值,谁调用get_time谁就拿res的返回值

练习(登录认证功能)

def index():
    print(5)  # 9、执行index函数
    print('from index')


def login_auth(func):
    print(6)  # 6、开始执行login_auth函数

    def auth(*args, **kwargs):
        print(7)  # 7、执行auth函数
        name = input('请输入你的名字>>>>').strip()
        pwd = input('请输入你的密码>>>>').strip()
        print(8)  # 8、 让用户输入认证的用户名和密码
        user_res = func(*args, **kwargs)  # 8、1调用index函数
        print(9)  # 10、执行完index
        if name == 'kevin' and pwd == '123':
            print(10)  # 11、通过判断条件,认证成功
            print('恭喜你登录成功')
            return user_res  # 11.1返回index内存地址给auth
        else:
            print('用户名或密码错误')
            print(11)

    print(12)  # 3、返回auth的内存地址
    return auth


print(1)  # 1、调用login_auth并且将index的内存地址赋给func
index = login_auth(index)
print(2)  # 4、将auth内存地址给index,在通过index赋值给res
res = index
print(3)
res()  # 5、调用auth函数
print(4)

装饰器模版

def outer(func):
    def inner(*args, **kwargs):
        print('函数执行前可操作的功能')
        uer_inner = func(*args, **kwargs)
        print('函数执行后可操作的功能')
        return uer_inner

    return inner

res = outer('')

Eg:做一个函数执行时间的装饰器
   
import time


def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        time.sleep(3)
        uer_inner = func(*args, **kwargs)
        end_time = time.time()
        print(f'函数执行了{end_time - start_time}秒')
        return uer_inner

    return inner


def index():
    print('》》》》index')


index = outer(index)
index()

装饰器的语法糖

"""
	1、语法糖其实就是一个装饰器,装饰器本质就是函数,函数其实就是一个个的功能!
	2、语法糖的书写规范:
		紧贴着被装饰对象的上方写
	3、语法糖的内部原理:
		它会自动把下面的被装饰对象的函数名当成参数自动传递调用装饰器
	4、如果语法糖执行完毕之后,没有其他语法糖了,我们要使用跟原函数同名的变量名命名
"""
"""装饰器本质就是函数,函数就是功能"""

# 语法糖
import time


def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        time.sleep(3)
        uer_inner = func(*args, **kwargs)
        end_time = time.time()
        print(f'函数执行了{end_time - start_time}秒')
        return uer_inner

    return inner


@outer  # 这个语法糖就相当于index = outer(index),我们只需要在下面直接用函数名加括号调用即可
def index():
    print('》》》》index')


index()  # inner()

双层语法糖

import time


def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        time.sleep(3)
        uer_inner = func(*args, **kwargs)
        end_time = time.time()
        print(f'函数执行了{end_time - start_time}秒')
        return uer_inner

    return inner


def user_auth(func):
    def login(*args, **kwargs):
        name = input('请输入系统管理员账号>>>>')
        pwd = input('请输入系统管理员密码>>>')
        if name == 'root' and pwd == '000000':
            print('欢迎进入管理员系统')
            user_login = func(*args, **kwargs)
            return user_login
        else:
            print('输入的信息有误')

    return login


@user_auth
@outer  # 这个语法糖就相当于index = outer(index),我们只需要在下面直接用函数名加括号调用即可
def index():
    print('》》》》index')


index()  # inner()

# 检测是自下而上检测的,执行是从上往下执行的

多用户登录认证

import time


def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        time.sleep(3)
        uer_inner = func(*args, **kwargs)
        end_time = time.time()
        print(f'函数执行了{end_time - start_time}秒')
        return uer_inner

    return inner


users_login = {'login': False}


def user_auth(func):
    def login(*args, **kwargs):
        if users_login.get('users_login'):
            user_login = func(*args, **kwargs)
            return user_login
        name = input('请输入系统管理员账号>>>>').strip()
        pwd = input('请输入系统管理员密码>>>').strip()
        if name == 'root' and pwd == '000000':
            print('欢迎进入管理员系统')
            user_login = func(*args, **kwargs)
            users_login['users_login'] = True
            return user_login
        else:
            print('输入的信息有误')

    return login


@user_auth
@outer  
def index():
    print('》》》》index')


@user_auth
@outer
def home():
    print('>>>>>home')


home()
index()  # inner()

'''
这段代码定义了一个字典变量`users_login`,用于存储用户登录状态。初始状态为`False`,表示用户未登录。

然后定义了一个装饰器函数`user_auth`,它接受一个函数作为参数,并返回一个新的函数`login`。`login`函数首先检查`users_login`字典中的`users_login`键的值是否为`True`,如果是,则说明用户已经登录,直接调用原始函数并返回结果。

如果`users_login`字典中的`users_login`键的值为`False`,则说明用户未登录,需要输入管理员账号和密码进行验证。如果输入的管理员账号和密码正确,则打印欢迎信息,调用原始函数并返回结果,并将`users_login`字典中的`users_login`键的值设置为`True`,表示用户已经登录。

如果输入的管理员账号和密码不正确,则打印错误信息。最后,返回新的`login`函数。
'''

装饰器的修复技术了解

'''
	关键代码:
			from functools import wraps
			@wraps(func
'''


from functools import wraps

def outer(func):
    # func = index
    @wraps(func)
    def get_time(*args, **kwargs):
        # func:index
        # 1. 在函数执行之前打一个时间点
        start_time = time.time()
        res = func(*args, **kwargs)  # index()  func('tony')
        # 2. 在函数执行完毕之后在打一个时间点
        end_time = time.time()

        # 3. 两个时间的差值就是函数的实际执行时间
        print("函数执行了:%s秒" % (end_time - start_time))
        return res

    return get_time

有参装饰器

# 有参装饰器就是带参数的装饰器
# 先前我们学习的装饰器就是无参装饰器:不到参数的装饰器
import time


def outer(func):
    def inner(*args, **kwargs):
        start_time = time.time()
        time.sleep(3)
        uer_inner = func(*args, **kwargs)
        end_time = time.time()
        print(f'函数执行了{end_time - start_time}秒')
        return uer_inner

    return inner


users_login = {'login': False}


def user(type):
    def user_auth(func):
        def login(*args, **kwargs):
            if users_login.get('users_login'):
                user_login = func(*args, **kwargs)
                return user_login
            name = input('请输入系统管理员账号>>>>').strip()
            pwd = input('请输入系统管理员密码>>>').strip()
            if type == 'fill':
                print('这个用户名和密码来自于文件')
            elif type == "MySQL":
                print('这个用户名和密码来自于MySQL')
            if name == 'root' and pwd == '000000':
                print('欢迎进入管理员系统')
                user_login = func(*args, **kwargs)
                users_login['users_login'] = True
                return user_login
            else:
                print('输入的信息有误')

        return login

    return user_auth


@user('fill')
@outer
def index():
    print('》》》》index')


index()


@user('MySQL')
@outer
def home():
    print('>>>>>home')


home()

'''
	这段代码实现了一个装饰器函数`outer`和一个装饰器函数`user`,用于统计函数执行的时间和用户登录验证。

`outer`函数接受一个函数作为参数,并返回一个新的函数`inner`。`inner`函数使用`time`模块和`time.sleep`函数,记录函数执行前后的时间差并打印执行时间。然后调用原始函数并返回结果。

`user`函数接受一个参数`type`,用于指定登录验证方式。`user`函数返回一个装饰器函数`login`,它接受一个函数作为参数,并返回一个新的函数`login_auth`。

`login_auth`函数实现了用户登录验证功能,首先判断用户是否已经登录,如果已经登录,则直接调用原始函数并返回结果。否则,根据`type`的值选择不同的验证方式,比如从文件、MySQL中读取用户名和密码等。如果验证通过,则打印欢迎信息,调用原始函数并返回结果。

在示例中,分别使用不同的用户名和密码验证方式装饰了两个函数`index`、`home`,并在装饰器上添加了`outer`装饰器,实现了函数执行时间的统计。
'''

标签:index,函数,Python,基础,time,print,login,装饰,def
From: https://www.cnblogs.com/chao0308/p/17446535.html

相关文章

  • Python之作用域
    作用域、函数对象和闭包作用域1、全局作用域内置名称空间+全局名称空间全局存货全局有效2、局部作用域局部名称空间局部存活局部有效3、global关键字作用: 声明全局变量###########################global"""在函数的内部不能直接修改外部的变量......
  • python基础15
    递归函数什么是递归函数递归就是直接或者间接调用自己的函数就是递归函数1#练习题2l=[1,[2,[3,[4,[5,[6,[7,[8]]]]]]]34defindex(l):5foriinl:6iftype(i)isint:7print(i)8else:9index(i)算法之......
  • python版本的“共轭梯度法”算法代码
    在看代码的过程中遇到了共轭梯度法这个概念,对这个算法的数学解释看过几遍,推导看过了,感觉懂了,然后过上一些日子就又忘记了,然后又看了一遍推导,然后过了一些日子也就又忘记了,最后想想这个算法的数学解释就不要再取深究了,毕竟平时也不太会用到,偶尔用到了只要保证代码会写也就OK了。 ......
  • (动力节点)老杜零基础Java笔记-第一章 学前准备
    Java零基础教程视频(零基础学Java必刷,适合Java0基础,Java初学入门)课堂截图为什么使用截图工具在听课的过程中,有的时候老师操作的比较快,通过截图的方式将老师的操作保存下来,以便后期的操作。另外截图之后的图片也可以用于笔记的记录,在笔记当中最好采用图文并茂的方式,这样更加利于......
  • 使用python操作hdfs,并grep想要的数据
    代码如下:importsubprocessfordayinrange(24,30):forhinrange(0,24):filename="tls-metadata-2018-10-%02d-%02d.txt"%(day,h)cmd="hdfsdfs-text/data/2018/10/%02d/%02d/*.snappy"%(day,h)print(c......
  • python cassandra 创建space table并写入和查询数据
     fromcassandra.clusterimportClustercluster=Cluster(["10.178.209.161"])session=cluster.connect()keyspacename="demo_space"session.execute("createkeyspace%swithreplication={'class':'SimpleStrategy&......
  • python berkeley DB操作——打开btree索引文件中的database
    打开BDB中某个索引中的数据库代码: frombsddb3importdbimportbsddb3asbsddbprintdb.DB_VERSION_STRINGmydb=db.DB()mydb.open('your_btree_db_filename','databsename',dbtype=db.DB_BTREE)rec=cur.first()whilerec:#printkeyvaluepri......
  • SpringBoot的基础
    1、获取配置文件的值:@Value的方式yml配置文件redis:host:199.22.22.341.1、用法1:普通用法@Value("${redis.host}")privateStringparamName;结果1.2、用法2:冒号(:)的作用冒号(:)的作用:当获取的值没有值时,返回冒号后的预设值默认值@Value("${redis......
  • c++面试 笔试基础知识学习记录
    1.int(*p)[4]和int*p[4]int(*p)[4],p是一个指针变量,指向一个存放4个int变量的一维数组,p+1是向后移动数组长度个字节大小,也就是向后移动4个int字节的大小。*(*(p+1)+2)=*(p[1]+2)int*p[4],等价于int*(p[4]),[]优先级高于*所以p首先是一个数组。即定义了一个指针数组,p就......
  • Java基础
    Java基础java简介Java是一门高级的面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂......