python---闭包、装饰器

闭包和装饰器是python中的概念,刚开始看时可能比较难理解,二者也是一个递进的关系,所以下面我先介绍闭包的概念,再解释装饰器的概念。

1、闭包

在"流畅的python"中对闭包有这样一句描述:闭包指延伸了作用域的函数,其中包含函数定义体的引用、但是不在定义体中定义的非全局变量。这里面最重要的概念就是延伸了作用域。那么接下来,如何理解闭包呢?

首先,需要知道什么是函数的嵌套,所谓嵌套就是函数内定义函数,也就是如下所示格式:

def outer():
    a = 200
    
    def inner():
        pass

理解了函数的嵌套,就明白了闭包的本质,闭包本质上就是嵌套函数,只不过闭包在嵌套函数的基础之上,规定:内部函数引用了外部变量;返回值是内部函数。也就是如下例子所示。

def outer(num):
    a = 10

    def inner():
        b = a + num  # 内部函数引用外部变量
        print("内部函数:", b)

    return inner  # 返回值是内部函数


r = outer(5)  # 调用函数,r接收返回值
r()  # 返回值是内部函数,所以r()实质上就是执行inner()


结果:
内部函数: 15

所以,这样我们就可以理解,为什么包指延伸了作用域的函数,在上面的例子中,在内部函数中调用了a,然后返回值是inner,实质上就是把a的作用域从outer函数中向外进行了延伸。

2、装饰器

装饰器是在闭包的基础之上的一个概念,在"流畅的python"中描述装饰器:装饰器是可调用的对象,其参数是另一个函数。也就是说,装饰器是一个把其他函数当作参数传入的函数。那么装饰器的作用是什么呢?其实,开发中遵循开放封闭的原则,在不改变原有代码或者函数的基础之上,装饰器可以扩展原函数的功能。

下面以一段代码说明装饰器的概念和用法。

import time
import random


# 简单的装饰器
def decorater(func):
    def wrapped(*args, **kwargs):  # 参数是为了应对各种带参或不带参的函数作为参数传入
        start = time.time()
        func(*args, **kwargs)
        print('刷白墙')
        print('铺地板')
        print('买家具')
        time.sleep(random.randint(1, 5))
        print('装修结束')
        end = time.time()
        print('装修花费的时间:', end-start)
    return wrapped


# 装饰有返回值的函数的装饰器
def decorater1(func):
    def wrapped(*args, **kwargs):
        start = time.time()
        r = func(*args, **kwargs)  # 原函数带有返回值,这儿需要变量进行接收
        print('预计装修花费:{}'.format(r))
        print('刷白墙')
        print('铺地板')
        print('买家具')
        time.sleep(random.randint(1, 5))
        print('装修结束')
        end = time.time()
        print('装修花费的时间:', end-start)
        return r+10000
    return wrapped


'''
原函数home(),开始并未装修,但是未来遵循开放封闭原则,不对原函数进行更改,
就用装饰器进行修改装修,装饰器实质上就将home()作为参数传入进去,
然后就可以对原函数内容进行各种添加和修改
也就相当于:home = decorater(home),由于decorater中的返回值是wrapped,
所以,执行完毕后,home实质上也就是wrapped()了
'''


@decorater
def home():
    print('买了一套房,没装修')


@decorater
def school(address, area):
    print('学校位于:{0},面积是:{1}'.format(address, area))


@decorater
def hotel(name, address, area):
    print('酒店叫:{0}, 酒店位于:{1},面积是:{2}'.format(name, address, area))


@decorater1
def factory(name, address, area):
    print('工厂叫:{0}, 工厂位于:{1},面积是:{2}'.format(name, address, area))
    return 50000


if __name__ == '__main__':
    home()
    print('-----------')
    school('北京', '1200')
    print('-----------')
    hotel(name='锦江之星', address='上海', area='1500')
    print('-----------')
    r = factory(name='苹果', address='加利福尼亚', area='150000')
    print('实际装修花费:{}'.format(r))


执行结果:
买了一套房,没装修
刷白墙
铺地板
买家具
装修结束
装修花费的时间: 4.01039457321167
-----------
学校位于:北京,面积是:1200
刷白墙
铺地板
买家具
装修结束
装修花费的时间: 1.0044851303100586
-----------
酒店叫:锦江之星, 酒店位于:上海,面积是:1500
刷白墙
铺地板
买家具
装修结束
装修花费的时间: 5.011623859405518
-----------
工厂叫:苹果, 工厂位于:加利福尼亚,面积是:150000
预计装修花费:50000
刷白墙
铺地板
买家具
装修结束
装修花费的时间: 4.006804943084717
实际装修花费:60000
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楊木木8023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值