python学习笔记:装饰器

python装饰器

在python的学习中,我们经常会遇到装饰器这个词。从他的名字看,起的作用应该是“装饰”,那么它具体是什么呢?今天我们就来分析一下。

基础知识

如果我们要学习装饰器,那么一定要了解内部函数和闭包的概念,因为可以这么说装饰器基于闭包实现,闭包基于内部函数实现。也可以说装饰器是闭包的一个应用。

1、内部函数

  • 内部函数大致格式
#定义函数func()
def func():
    #函数func()变量声明(局部/全局)
    #函数func()中其他函数体,除内部函数以外
    def inner_func(): #声明内部函数,内部函数可以看做是函数体
        #内部函数变量声明(局部/全局)
        #内部函数inner_func()函数体

    # 调用内部函数inner_func()
        inner_func()#如果不这样操作,则inner_func()函数永远不会被调用

#调用函数func()
func()
  • 内部函数的特点

(1)可以直接访问外部函数的变量

(2)内部函数修改全局不可变变量时,需要在内部函数使用关键字global,格式:global 变量名

(3)内部函数修改外部函数的不可变变量时,需要在内部函数中使用关键字nonlocal,格式:nonlocal 变量名

(4)内部函数可以直接修改外部函数的可变类型的变量,不借助其他关键字

2、闭包

  • 闭包是在内部函数的基础提出的概念,一般需要满足以下条件的函数是闭包。

(1)外部函数中定义了内部函数

(2)外部函数有返回值,且返回值是内部函数名(注意:返回是你函数名,inner_func,而不是inner_func(),带了()就是函数的调用了)

(3)内部函数引用了外部函数的变量

  • 大致格式
#定义
def func():
    ...
    def inner_func():
        ...
    return inner_func#不带()

#调用func().返回的是inner_func()这个名字
inner_func_name=func()

#调用返回出来的内部函数inner_func()
inner_func_name()
  • 闭包的作用:
    (1)可使用同级的作用域
    (2)读取其他元素的内部变量
    (3)延长作用域

装饰器

在有了上面的知识之后,我们就可以开始介绍了装饰器了。

1、最简单的装饰器

我们首先来介绍最简单的装饰器,就是不带参数且只有一层的那种。

装饰器的一个最简单用处就是进行校验,当大家优酷等软件上下载视频时,是需要处于登录状态的,假设说没有登录,系统会提示,请登录后进行下载。

对于上面的例子我们进行抽象,可以得到以下模块:
(1)登录
(2)判断是否登录
(3)下载

那么假设,我们现在已经有了登录函数和下载函数(如下),那么怎么才能完成程序要求呢?

# islogin代表用户是否登录,False未登录,True已经登录
# 默认登录名:user   默认密码:user
import time

islogin = False


# 登录函数
def login():
    # 登录时的用户名和密码由键盘提示输入
    print("正在登录中......")
    username = input("username:")
    password = input("password:")
    if username == 'user' and password == 'user':
        print("登录成功,欢迎使用!")
        return True  # 用户密码匹配成功,True置1,登录成功
    return False

# 下载函数(不涉及实现,只是提示)
@login_result  # 声明装饰器@+装饰的函数名
def download():
    print("下载已开始,请您耐心等待!")
    for i in range(3, 0, -1):
        print("倒计时:", i)
    print("下载已经完成,可前至缓存中查看!")

当然,最粗暴简单的方法就是重写,将判断登录的功能写进去,但是那样的话,有些浪费时间,而且有些代码是不允许我们随心篡改的,比如:某工程的核心代码,一改动工程就瘫痪了。

这时我们需要另外一种比较简单方法来解决这个问题,这个方案就是装饰器。因为装饰器的作用就是在原有函数的基础上,去扩展该函数的功能。

我们先来介绍一下装饰器的格式特点:闭包+参数是函数。

那么我们现在用装饰器的方式来完成上面的功能要求。

注意:在使用装饰器的时候,我们要修饰哪个函数(给哪个函数扩展功能)就在哪个函数上面添加@+修饰函数的名字。

# islogin代表用户是否登录,False未登录,True已经登录
# 默认登录名:user   默认密码:user
import time

islogin = False


# 登录函数
def login():
    # 登录时的用户名和密码由键盘提示输入
    print("正在登录中......")
    username = input("username:")
    password = input("password:")
    if username == 'user' and password == 'user':
        print("登录成功,欢迎使用!")
        return True  # 用户密码匹配成功,True置1,登录成功
    return False


# 装饰器的实现函数:login_result()
def login_result(download):  # 参数是函数
    def ornament(*args, **kwargs):  # 使用可选参数,可以接受所有类型的参数
        global islogin  # 如果登录状态变更,需要进行修改,所以用global进行声明
        if islogin:  # 判断是否登录
            download(*args, **kwargs)  # 登录时执行
        print("您还没有登录,请登录后重新进行下载!")
        while islogin != True:
            islogin = login()  # 没有登录时执行

    return ornament  # 内部函数名


# 下载函数(不涉及实现,只是提示)
@login_result  # 声明装饰器@+装饰的函数名
def download():
    print("下载已开始,请您耐心等待!")
    for i in range(3, 0, -1):
        print("倒计时:", i)
    print("下载已经完成,可前至缓存中查看!")


# 调用
download()
download()

在这里插入图片描述
从上面的程序,我们可以知道@login_result 的执行过程:
(1)明确被装饰函数是紧跟在它下面的函数(download)
(2)将被装饰函数作为参数传递给装饰器login_result函数
(3)执行装饰器login_result函数

用图解的方式展示一下:
在这里插入图片描述

2、多层装饰器

对一个函数的功能扩展是可以用好几个装饰器共同实现的,实现起来也很简单,就是定义了装饰器函数后,在需要被装饰的函数上面声明装饰器相当于简单装饰器的叠加。所以不展开叙述。

@装饰器1名称
@装饰器2名称
......
@装饰器n名称
def 被装饰函数名(参数列表):

注意:在多层装饰器的使用上,我们要注意就近原则,就是说离被修饰越近的函数(从底向上),越先被加载修饰,即n——>1的顺序。

3、带参数的装饰器

带参数的修饰器和简单修饰器相比,多了参数,它的格式也发生了相应的变化,但是实现机制没有区别。

  • 带参数的装饰器特点如下:
    (1)带参数的装饰器结构是三层的
    (2)最外层的函数负责接收装饰器参数
    (3)里面的内容还是原来装饰器的内容,并没有发生变化

  • 带参数的装饰器格式:

#带参数的修饰器函数的实现
def ceng1(num):#第一层:接收装饰器的参数
    def ceng2(func):#第二层:接收被装饰函数
        def ceng3(*args,**kwargs):#第三层:接收函数参数
            #函数体
        return ceng3 #返出第三层的函数名
    return ceng2 #返出来第二层的函数名

@ceng1(5)#带参数装饰器的声明
def download():
    #函数体
#调用
download()

其实不管是哪种装饰器,他们起的作用在本质上是一样的,都是在不改动原有函数的基础上,对被修饰函数做功能上的扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值