Python闭包函数以及装饰器函数w1的应用

1.闭包函数

1.定义

内部函数对外部函数作用域中的变量的引用

2.闭包函数定义格式

  1. 函数B()在函数A()的内部定义
  2. 函数B中的变量可以是函数A的变量
  3. 函数A的返回值必须是函数B的引用**(名字不带括号)**

例如:在下图例子中,func()就是外部函数inner()就是内部函数(闭包函数)。函数func()的返回值是inner这个函数,因此可以理解为func(10)他不是一个值,而是一个函数。

def func(n1):
    print("func  start")
    def inner(n2):
        print("inner  start")
        return n1+n2
    print("func  end")
    return inner
temp=func(10)(5)
print(temp)
#上面两行还可以以写成
#temp=func(10)
#print(temp(5))

3.闭包函数的调用

在上图例子中,运行结果为:

func  start
func  end
inner  start
15

例如:写一个一元一次函数y=ax+b的运行程序,a,b,x均自定义。在正常情况下,函数在调用并执行完之后内部的变量就会返还给系统,但是在闭包函数中,先执行完了func()函数,但是再执行inner()函数时还是可以获取到a,b的值的。因此闭包函数保存了外部函数变量的值,延长了这些变量的生命周期。代码如下:

def func(a,b):
    def inner(n2):
        return a*x+b
    return inner
#求解y=2x+3,当x=1时
temp1=func(2,3)
print(temp1(1))

def f():
    a=1
    def inner():
        b=a+1
        return b
    return inner

又例如上图的闭包函数运行是正确的。但是把b改成a之后就会报错,因为你如果把b改成a之后,当出现a=a+1时,该等式左边出现的变量a会被认为是一个局部变量;导致系统会认为等式右边的a和左边的a是同一个,那么系统就会去寻找,发现在inner内部函数里面没有定义a,在inner()括号的形参里面也没有a,因此就会报错,所以尽量避免重名。一定要使用重名的话可以使用下面的代码:

def f():
    a=1
    def inner():
        nonlocal a
        #上面这条语句的意思就是指明等号右边的a不是和内部函数中的a一样属于inner的局部变量,而是外部变量。
        a=a+1
        return b
    return inner

2.装饰器

1.概述

装饰器就是闭包函数的一种应用。它是一个嵌套的函数,内部是闭包函数,外部函数接收的是被装饰的功能函数f,闭包里面增加扩充功能,然后执行函数的调用。它的需求是在不改动函数的前提下,对函数的功能进行扩充。必须遵守"封闭开放"原则:

  • 封闭函数功能已经完成的情况下,需要添加新功能,原则上不去改动函数本身。(函数封装后无法改动)
  • 开放:函数功能根据需要能够不断更新,添加新功能。

例如,在函数:

def func():
    print("hello")

的基础之上再添加功能,打印输出系统时间,代码如下:

import time
#装饰器函数
def w1(f):
    def inner():
        f()
        print(time.ctime())
    return inner
def func():
    print("hello")
temp=w1(func)
temp()

初始功能函数为func(),其实装饰器函数就相当于自定义的一个函数w1,把初始功能函数作为参数传进去,然后在w1的内部闭包函数里面写上初始功能函数以及添加功能函数print(time.ctime())。或者还有另外一种形式改写最后两行并用上@符号,代码如下:

import time
#装饰器函数
def w1(f):
    def inner():
        f()
        print(time.ctime())
    return inner
@w1
def func():
    print("hello")
func()

2.装饰器的定义步骤

  1. 有一个初始功能函数func(),需要增加新功能。
  2. 定义一个函数w1,形参接收一个函数名
  3. 在w1里定义闭包函数inner,在inner调用w1的形参(其实就是调用初始功能函数),并增加新的功能。
  4. 自定义函数w1的返回值闭包函数inner
  5. 在函数func()前面使用@w1来表示装饰器的调用

补充:另外如果你想要输出函数名的话,可是使用f._name_方法来表示函数的函数名。

3.装饰器装饰各种不同的函数

1.装饰无参函数

def w1(f):
    def inner():
        f()
        print(time.ctime())
        #print("{}函数正在执行".format(f.__name__))
    return inner
def func():
    print("hello")
temp=w1(func)
temp()

2.装饰有参数的函数

def w1(f):
    def inner(a,b):
        print("函数正在运行");
        f(a,b)
    return inner
@w1
def func(a,b):
    print(a+b)
func(11,22)
#输出结果为33

如上图,func(11,22)被装饰后,调用的是w1里的inner函数;inner函数必须接收相同个数的参数;inner里把参数传递给被装饰的函数。

3.装饰不定长参数的函数

def w1(f):
    def inner(*args):
        print("函数正在运行");
        f(*args)
    return inner
@w1
def func1(a,b):
    print(a+b)
def func2(a,b,c):
    print(a+b+c)
func1(11,22)
#输出结果为33
func2(11,22,33)
#输出结果为66

4.装饰有返回值的函数

def w1(f):
    def inner(*args):
        print("函数正在运行");
        return f(*args)
    return inner
@w1
def func1(a,b):
    print(a+b)
x=func1(11,22)
print(x)
#输出结果为33

闭包函数inner有返回值时,在执行函数时要用变量去接收函数值。否则无法输出相应内容。有返回值的函数必须在被装饰的时候也有返回值

5.通用性装饰器

def w1(f):
    def inner(*args,**kwargs):
        print("函数正在运行");
        return f(*args,**kwargs)
    return inner

6.装饰器带参数

def w(x):
    def w1(f):
        def inner(*args,**kwargs):
            print("{}正在运行".format(x));
            return f(*args,**kwargs)
        return inner
    return w1
@w("张三")
def func(a,b):
    return a+b
x=func(11,22)
print(x)

当装饰器带参数时,可以在外面再包一层函数定义参数用来传递装饰器的参数装饰器的参数不能在w1中传递,w1的参数只能是初始功能函数名

猜你喜欢

转载自blog.csdn.net/Aurora_1970s/article/details/105714236