闭包和装饰器

Jupyter notebook点击有奖

1、闭包

  • 什么是闭包:内部函数对外部函数作用域里的非全局变量的引用,称【内部函数】为闭包。
  • 闭包三要素:1、嵌套函数;2、变量引用;3、返回内部函数
def fun(n):
    def fun_in(m):
        print("sum = ",n+m)#内部函数对外部函数的变量的引用(n)
        return n,m
    return fun_in
f = fun(10)    # 这里f 为函数fun()的返回值,及fun_in的地址
f
<function __main__.fun.<locals>.fun_in(m)>
# 要想调用函数,只需要加上括号并传入相关的参数即可
f(100)
sum =  110





(10, 100)

使用

  • 下面的代码定义了一个一次函数y = ax+b,其中a,b为参数,我们可以i对其进行指定:
def fun(a,b):
    def fun_in(x):
        return a*x + b
    return fun_in
f = fun(2,3)
f
<function __main__.fun.<locals>.fun_in(x)>
f(10)#2*10+3
23
#也可以直接调用
fun(4,10)(10)
50

2、装饰器

  • 首先,放出来那两篇博客的链接,大家可以去看看,保证有所收获!python装饰器详解Python 装饰器的通俗理解
  • 功能:简单来说,装饰器的作用就是在已经定义了某个函数之后,后期我们希望为该函数增加新的功能,但是碍于代码已经上线运行等原因,我们不能直接在源代码上直接修改。从中可以看出有以下几点:
    • 1、不修改原来的核心代码
    • 2、不能改变核心代码的调用方式
    • 3、给核心代码增加新的功能

高级函数

  • 首先需要知道函数名和变量名在实际上就是一个地址。高级函数可以分为:
    • 1、函数的参数是一个函数
    • 2、函数的返回值是一个函数
  • 还有就是区分函数定义和函数调用,下面举个例子:
def func1():
    def func2():
        print('call func2')
    print('call func1')
func1()
call func1
  • 注意上述代码并没有打印出call func2,这里可以这样理解,func1()的功能就是定义func2,并打印call func1
def func1():
    def func2():
        print('call func2')
    func2()
    print('call func1')
func1()
call func2
call func1
  • 上述代码可以理解为有两个功能:一个是定义func2,一个是调用func2.
# 该函数在两秒之后打印内容
import time
def test():
    time.sleep(2)
    print("test is running")
test()
test is running
  • 现在需要增加该函数的功能,计算该函数的运行时间,但是不可以改变test()函数
import time
def test():
    time.sleep(2)
    print("test is running")
def deco(func):
    start = time.time()
    func()
    stop = time.time()
    print(stop - start)
deco(test)
test is running
2.000415325164795
  • 上述代码中deco()函数其实就是一个高级函数,它的参数为一个函数。
    * 但是上面的函数虽然实现了增加功能的要求,但是它改变了函数的调用方式,原来我们是调用test()函数,我们像不改变调用方式,怎么办呢?
import time
def test():
    time.sleep(2)
    print("test is running")
def dec(func):
    print(func)
    return func
dec(test)()
<function test at 0x06383150>
test is running
  • 上面的dec()函数也是一个高级函数,它的返回值是一个函数。但是它并没有增加我们需要的功能。

嵌套函数

  • 嵌套函数是指在函数内部定义函数,注意不是调用函数
# 定义函数
def func1():
    def func2():
        pass
    pass
# 调用函数
def func1():
    func2()
    pass
import time
def test():
    time.sleep(2)
    print("test is running")
def timer(func):
    def deco():
        start = time.time()
        func()
        stop = time.time()
        print(stop-start)
    return deco
test = timer(test)       #1
test()                   #2
test is running
2.000458002090454
  • #1处调用timer()函数,并返回了deco,赋值给test,此时test实际上就是函数deco()的入口地址

  • #2处在test后面加上(),实际上完成了对test()函数的调用,也即deco()函数的调用。

  • 实际上上面的函数也是一个闭包,它满足了闭包的三个条件

  • 装饰器可分为对【有无参数】函数进行装饰的装饰器和对有【无返回值函数】进行装饰的装饰器,组合起来一共有4种。即:装饰器对无参数无返回值的函数进行装饰,装饰器对无参数有返回值的函数进行装饰,装饰器对有参数无返回值的函数进行装饰,装饰器对有参数有返回值的函数进行装饰。

对无参数的函数进行装饰

import time
def timer(func):
    def deco():
        start = time.time()
        func()
        stop = time.time()
        print(stop-start)
    return deco
@timer
def test():
    time.sleep(2)
    print("test is running")
test()
test is running
2.000509738922119
  • 使用装饰器既增加了函数的功能,又没有改变调用方式(还是调用的test())

对有参数的函数进行装饰

def timer(func):
    def deco(args):
        start = time.time()
        func(args)
        stop = time.time()
        print(stop-start)
    return deco
@timer
def test(args):
    time.sleep(args)
    print("test is running")
test(3)
test is running
3.0000321865081787

1、装饰器对无参数函数进行装饰

#对字体加粗
def makeBold(fn):
    def wrapped():
        return "<b>"+fn()+"</b>"
    return wrapped

#斜体字处理
def makeItalic(fn):
    def wrapped():
        return "<i>"+fn()+"</i>"
    return wrapped
@makeBold
def test1():
    return "hello"

@makeItalic
def test2():
    return "world"

@makeBold
@makeItalic
def test3():
    return "hello world"
test1()
'<b>hello</b>'
test2()
'<i>world</i>'
test3()
'<b><i>hello world</i></b>'
  • 上面的代码是做网页时对字体进行处理。注意:可以对一个函数同时使用多个装饰器,装饰的顺序由内而外

2、装饰器对有参数的函数进行装饰

def deco(func):
    def wrapped(a,b):
        print('在此处增加功能')
        func(a,b)
    return wrapped
@deco
def sum(a,b):
    print(a+b)
sum(10,20)
在此处增加功能
30
  • 当装饰器装饰有参数的函数时,装饰器内部的函数也必须带有和其相同的参数,因为被装饰的参数会被当成参数传进装饰器的内部函数中,如果两者的参数不一致,会报错。

3、装饰器对不定长的参数函数进行装饰

from time import ctime,sleep
def deco(func):
    def wrapped(*args, **kwargs):
        print("{} is called at the time: {} ".format(func.__name__,ctime()))
        func(*args,**kwargs)
    return wrapped
@deco
def test1(a,b,c):
    print(a+b+c)

@deco
def test2(a,b):
    print(a*b)
test1(1,2,3)
test1 is called at the time: Thu Nov 29 19:25:07 2018 
6
test2(2,4)
test2 is called at the time: Thu Nov 29 19:25:15 2018 
8

4、装饰器对有返回值的函数进行装饰

from time import ctime,sleep
def deco(func):
    def wrapped(*args, **kwargs):
        print("{} is called at the time: {} ".format(func.__name__,ctime()))
        return func(*args,**kwargs)
    return wrapped
@deco
def test():
    return "hello"
test
<function __main__.deco.<locals>.wrapped(*args, **kwargs)>
test()
test is called at the time: Thu Nov 29 19:30:34 2018 





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值