首页
学习
活动
专区
工具
TVP
发布

python由闭包到装饰器

在把函数当作对象的语言(python、javascript)中闭包的概念肯定是少不了的。

闭包的定义在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。

实例

defEx(count):

print(count)

defe():

# 内部函数==>用了外部函数的变量

returncount+1

returne

外函数返回了内函数的引用

外函数把临时变量绑定给内函数

修改变量【非常重要】

想一下python中是如何修改全局变量的?

采用global关键词

将全局变量改为可变的数据类型

可变的数据类型:list 、dict set 【复习笔记中有详细说明】

同理python闭包中内函数如何修改?

python3中加入了nonlocal 关键字

采用可变的数据类型【python2 只能采用这种策略了】

使用

defcounter(start_at=):

count=[start_at]

defincr():

count[]+=1

returncount[]

returnincr

一个简单的计数器实现计数功能!

>>>c=counter(10)

>>>c()

11

>>>c()

12

>>>

python3 中的实例

>>>defcounter(s):

defadd():

nonlocals

s+=1

returns

returnadd

>>>c=counter(10)

>>>c()

11

>>>c()

12

闭包的作用

装饰器是不是很像呢?

面向对象属性和方法

单例模式没用过(难受)

闭包的优缺点

优点:提高代码的复用性

缺点:

由于闭包引用了外部函数的局部变量,外部函数的局部变量没及时释放,消耗内存

闭包类似于实例对象一样,是一个独立空间,多个闭包就是多个各自独立的空间,互不影响

闭包占用的内存空间要远小于一个实例对象的空间,因此在需要一个独立空间(需要变量+功能)时,除了考虑实例对象之外,还可以考虑闭包

关于闭包的补充

一切都是对象来说,闭包也有个不得不说的属性即:closure属性定义的cell对象

c=counter()

c()

print(c.__closure__[].cell_contents)

c()

print(c.__closure__[].cell_contents)

# 输出 1 2

装饰器

在有了前面闭包的理解,下面的装饰器用一个实例引入,比如说我要添加一个自动计数的功能该如何实现?

用闭包实现

defcounter(start_at=):

count=start_at

defincr():

nonlocalcount

count+=1

returncount

returnincr

c=counter()

defoutput():

'''

一堆输出操作

'''

print(" %d times"%c())

importtime

whileTrue:

output()

time.sleep(2)

但是,再用闭包实现时,要改动output()函数中的代码哈,如果不想改变output中的代码该怎么办呢?这就用到装饰器了!

装饰器定义

在不修改原函数的代码的情况下,添加新的功能。可以在执行原函数之前加,也可也在执行原函数之后添加

装饰器用法

defcounter(func,count=):

defwrapper():

func()

nonlocalcount

count+=1

print(" %d times"%count)

returnwrapper

importtime

@counter

defoutput():

time.sleep(2)

whileTrue:

output()

跟闭包差不多,却把函数当参数传递进去了!这就是无参函数的基本用法

函数带参数

# -*- coding: utf-8 -*-

fromtimeimportctime

fromtimeimportsleep

defftfunc(func):

deftimef(*s,**gs):

print"[%s] %s() called"%(ctime(),func.__name__)

returnfunc(*s,**gs)

returntimef

@ftfunc

deffoo(*s,**gs):

print(s)

print(gs)

if__name__=='__main__':

foo()

foo(1)

foo(1,2)

foo(1,2,3)

stu= {'name':'alam','age':12}

foo(1,2,3,**stu)

'''

运行结果

[Wed Jun 14 15:49:55 2017] foo() called

()

{}

[Wed Jun 14 15:49:55 2017] foo() called

(1,)

{}

[Wed Jun 14 15:49:55 2017] foo() called

(1, 2)

{}

[Wed Jun 14 15:49:55 2017] foo() called

(1, 2, 3)

{}

[Wed Jun 14 15:49:55 2017] foo() called

(1, 2, 3)

{'age': 12, 'name': 'alam'}

[Finished in 0.1s]

'''

装饰器带参数

# -*- coding: utf-8 -*-

defdecrator(*dargs,**dkargs):

defwrapper(func):

def_wrapper(*args,**kargs):

print"decrator param:",dargs,dkargs

print"function param:",args,kargs

returnfunc(*args,**kargs)

return_wrapper

returnwrapper

@decrator(1,a=2)

deffoo(x,y=):

print"foo",x,y

if__name__=='__main__':

foo(3,4)

'''

执行结果

decrator param: (1,) {'a': 2}

function param: (3, 4) {}

foo 3 4

[Finished in 0.1s]

'''

带返回值的装饰器

defcounter(func,count=):

defwrapper():

func()

nonlocalcount

count+=1

print(" %d times"%count)

returncount

returnwrapper

importtime

@counter

defoutput():

time.sleep(2)

whileTrue:

a=output()

print(a)

多装饰器

importlogging

defcounter(func,count=):

defwrapper():

func()

nonlocalcount

count+=1

print(" %d times"%count)

returncount

returnwrapper

deflog(func):

defwrapper():

logging.warning("warning test %s"%func.__name__)

return

returnwrapper

importtime

@log

@counter

defoutput():

time.sleep(2)

whileTrue:

a=output()

print(a)

time.sleep(5)

装饰器是递归输出的!同时可判断! 先输出log 在输出times 返回值是先用那个装饰器就返回谁的

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190209G0FG4000?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券