python3之装饰器(闭包)实现 上篇

装饰器是python中一个强大的功能,利用装饰器可以在不必改动原有函数的前提下增加一些功能,可以被用于日志记录、权限验证、调试测试、事务处理等。装饰器是闭包的一种形式,闭包是python函数编程的高级用法,学习闭包之前让我们先了解python函数的概念理解和高级用法。本篇文章会结合闭包的形式和装饰器的使用分为上下两篇。

概念理解

<1>变量可以指向函数,函数对象和执行函数的定义

def add(x,y):
	return x+y

fn = add
fv = add(3,3)
print(add)
print(fn)
print(fv)
print(add(2,3))	
print(fn(4,5))

执行结果:

<function add at 0x0000019ED6503840>
<function add at 0x0000019ED6503840>
6
5
9

解析:代码<1>中定义了一个add()函数,打印add可以输出函数对象,打印add()输出函数执行后的结果。同时变量fn可以指向函数add,通过变量fn()可以调用add()函数。变量fv指向了执行函数add(3,3),打印出函数执行后的结果。

python函数高级用法

<1>函数可以作为参数进行传递

def add(x, y, f):
    return f(x) + f(y)
print(add(-5, 6, abs))

执行结果

11

<2>函数作为结果值返回

def sum(x,y):
	def cal():
		return x+y
	return cal

f = sum(3,5)
print(f())

执行结果:

8

解析:代码<2>中f调用执行sum()函数,函数cal对象作为返回值,此时x+y并没有执行,f()调用执行cal()函数,打印计算x+y结果。f调用执行sum()函数,同时接收sum()函数的返回值,此时 f=cal

为了说明闭包和嵌套函数的不同,让我们先看下两段代码,同时引入函数变量作用域的概念。
<1>

x = 0 # 模块级别定义的全局变量
def outer():
	x = 1 # 嵌套中父级函数的局部作用域变量
	def inner():
		x = 2 # 函数中定义的变量
		print("local: x=",x)
	inner()
	print("enclosing: x=",x)


outer()
print("global: x=",x)

执行结果:

local: x= 2
enclosing: x= 1
global: x= 0

解析:代码<1>即平常使用的函数嵌套,python允许出现同名变量,具有相同命名标识的变量在同一函数体中或具有函数嵌套关系,则不同作用域的变量各自代表不同的对象。 如果函数嵌套使用时,内部的inner函数需要传入参数该如何实现,我们来看接下来的代码。
<2>

def outer(x):
    def inner(y):
        print(x + y)
    return inner

f = outer(5)
f(10)

解析:代码<2>中函数inner作为结果返回。若调用某函数时,该函数将其内部定义的函数作为返回值,则所返回的函数称为闭包。f调用执行outer()函数,同时接收outer()函数的返回值,此时 f=inner,f(10)打印输出15(5+10=15)

归纳:函数中,谁调用执行函数,同时接收执行函数的返回值。闭包的特点在于从外部能向内部的函数传递参数。

闭包的注意点
闭包引用了外部函数的局部变量,外部函数的局部变量没有及时释放,消耗内存。看下面的代码:
<1>

def counter():
    s = 0
    def inner():
        nonlocal s # 声明父级函数的局部变量
        s += 1
        return s
    return inner

f = counter()
print(f())
print(f())

执行结果

1
2

<2>

def count():
    lists = []
    def inner(x=0):
        lists.append(x)
        return len(lists)
    return inner

f = count()
print(f(),f(),f())

执行结果

1 2 3

<3>

def get_avg():
    data = []
    def add_number(value):
        data.append(value)
        return sum(data)/len(data)
    return add_number

f = get_avg()
print(f(100))
print(f(200))

执行结果

100.0
150.0

解析:返回函数引用的变量可以被修改。

利用闭包实现装饰器
<1>示例代码

def add(x,y):
    return x+y

print(add(2,3))

执行结果:

5

如果此时我们需要在函数执行前打印出函数的参数,又不想改变原来的代码,应该怎么做呢?可以使用装饰器去实现。
<2>

def decorator(f):
    def wrapper(x,y):
        print("参数1为:%s,参数2为:%s"%(x,y))
        return f(x,y)
    return wrapper
@decorator
def add(x,y):
    return x+y

print(add(2,3))

执行结果:

5

这种语法结构就是装饰器,遵循了代码编写的开放封闭原则,即已经实现的功能代码不允许被修改,但可以被扩展。虽然在这个原则是用的面向对象开发,但是也适用于函数式编程。
关于装饰器的内部原理和高级用法,我们在python之装饰器下篇介绍。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值