6-闭包和装饰器

一、函数参数

  • 函数名存放的是函数所在的空间地址

  • 地址中存放的是函数中的代码

  • 函数名也可以像普通变量一样赋值

def func01():
    print("func01")

def foo(func)  
	func()  #【func()相当于func01()】
   
#函数名存放的是函数所在的地址
print(func01)  # <地址:0x11>
#函数名也可以像普通变量一样赋值
func02 = func01
func02()  # func01

foo(func01)  #将func01的地址赋值给func,执行函数中的代码

二、闭包

1.概念及作用

2.闭包的定义

  • 定义:在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们吧这个使用外部函数变量的内部函数称为闭包

  • 构成条件1)在函数嵌套的前提下

2)内部函数使用外部函数的参数

3)外部函数返回内部函数

# 1.在函数嵌套的前提下
def func_out(num1):
	def func_inner(num2):
# 2.内部函数使用外部函数的参数
    	num = num1 + num2
# 3.外部函数返回内部函数
    return func_inner

# 创建闭包实例
f = func_out(10)  #执行func_out(10),使num1 = 10,返回func_inner,使f = func_inner,即f() = func_inner()
# 执行闭包
f(1)  # 11  执行f(1)相当于执行func_inner(1),使num2 = 1, 运行函数内代码num = 11
f(2)  # 12

3.闭包的使用

  • 不仅能保存外部函数的变量,还可以增加函数的复用率
def people(name):
    def say(info):
        print(name + ':' + info)
    return say

tom = people('tom')
jerry = people('jerry')
tom('你好')
jerry('你好')
tom('你在吗')
jerry('我在呢')

4.nonlocal闭包内修改外部变量

  • 闭包中使用的外部函数变量相当于在内部函数中创建一个新的同名变量,如果要修改外部变量要使用nonlocal声明变量为外部函数的变量
def out_func(num):
    def inner():
        nonlocal num
        num = 12
        print(num)
    return inner

三、装饰器

1.装饰器定义

  • 作用:在不改变原有代码的情况下,给函数增加新的功能

2.装饰器的使用

  1. 定义一个装饰器(本质是闭包)
  2. 使用装饰器装饰函数
    • 装饰器语法糖:@装饰器名称
# 定义一个装饰器(本质是闭包)
def check(fn):
    def inner():
        print('验证码')
        fn() # 第三步:执行comment()
   	return inner

# 使用装饰器装饰原有函数
# @check 相当于 comment = chek(comment),解释器会自动执行
@check  
def comment():
    print('发表评论')

# comment = chek(comment)  # 第一步:执行check函数,将comment传入使fn = comment,即fn() = comment();同时返回inner,使comment = inner,即 comment() = inner()
comment()  # 第二步:执行 inner()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kx06ctdD-1604711802557)(C:\Users\lzq\AppData\Roaming\Typora\typora-user-images\image-20200902115132377.png)]

3.统计程序执行时间

import time

def get_time(fn):
    def inner():
        start = time.time()
        fn()  # 将要执行的函数用装饰器装饰起来 
        end = time.time()
        print(end - start)
    return inner

@get_time
def func():
    for i in range(10000):
        for n in range(100):

func()
# 4.014223575592041

4.通用版装饰器推导

1)装饰带有参数的函数

# 定义装饰器
def logging(fn):  # fn = sum_num    
    def inner(a, b):
        fn(a, b)
    return inner  # sum_num = inner
#使用装饰器装饰函数
@logging
def sum_num(a, b):
    result = a + b
    print(result)
    
sum_num(1, 2)  # 3

2)装饰带有返回值的函数

  • 当有返回值时,要注意返回值给了谁,地址已经改变,返回值最后应该给到sum_num
# 定义装饰器
def logging(fn):  # fn = sum_num    
    def inner(a, b):
        # fn(a, b)sum_num
        return fn(a, b)  #需要将函数中的返回值在返回给sum_num,才能正确输出
    return inner  # sum_num = inner
#使用装饰器装饰函数
@logging
def sum_num(a, b):
    result = a + b
    return result
    
result = sum_num(1, 2)  # sum_num的地址已经改变,变为inner的地址,所以没有返回值
print(result)  # None

3)装饰带有不定长参数的函数

# 定义装饰器
def logging(fn):  # fn = sum_num    
    def inner(*args, **kwargs):
        fn(*args, **kwargs)
    return inner  # sum_num = inner
#使用装饰器装饰函数
@logging
def sum_num(*args, **kwargs):
    print(args, kwargs)
    
sum_num(1, 2)
通用装饰器
# 定义装饰器
def logging(fn):
    def inner(*args, **kwargs):
        result = fn(*args, **kwargs)
        return result
    return inner

5.多个装饰器

  • 装饰顺序为:离函数最近的装饰器先装饰,然后外面的装饰器在装饰,由内到外的装饰顺序
# 定义装饰器1
def check1(fn1):					# 3.fn1 = inner2
    def inner1():
        print('登陆验证1')
        fn1()
    return inner1					# 4.comment = inner1

# 定义装饰器2     
def check2(fn2):					# 1.fn2 = comment
    def inner2():
        print('登陆验证2')
        fn2()
    return inner2					# 2.comment = inner2

@check1
@check2
def comment():
    print('发表评论')
    
comment()							# 5.comment() = inner1()

6.带有参数的装饰器

  • @logging(’+’)执行步骤
    1. logging("+")
    2. @decorator起到装饰器的功能了
# 装饰器
def logging(flag):  # flag = "+"
    # 外部函数
    def decorator(fn):
        # 内部函数
        def inner(num1, num2):
            # 判断流程
            if flag == "+":
                print("--正在努力加法计算--")
            elif flag == "-":
                print("--正在努力减法计算--")
            result = fn(num1, num2)
            return result
        return inner
    # 返回装饰器
    return decorator

# 被带有参数的装饰器装饰的函数
@logging('+')  # 1 logging("+")   2 @decorator起到装饰器的功能了
def add(a, b):
    result = a + b
    return result

# 执行函数
result = add(1, 3)
print(result)

7.类装饰器

1.call方法
class Check(object):
    def __call__(self, *args, **kwargs)
    	print('这是一个call方法')

c = Check()
c()  # 实例对象加(),即对象函数会自动调用__call__方法。
2.类装饰器
# 定义类装饰器
class Check(object):
    def __init__(self, fn):  # fn = comment
        self.__fn = fn

    def __call__(self, *args, **kwargs):
        print("登陆")
        self.__fn()  # comment()


# 被装饰的函数
@Check  # comment = Check(comment)  comment就是一个实例对象
def comment():
    print("发表评论")


comment()  # 实例对象()会自动调用__call__方法

mment
self.__fn = fn

def __call__(self, *args, **kwargs):
    print("登陆")
    self.__fn()  # comment()

被装饰的函数

@Check # comment = Check(comment) comment就是一个实例对象
def comment():
print(“发表评论”)

comment() # 实例对象()会自动调用__call__方法


























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值