转自小马哥:

闭包和装饰器充分体现了Python语法糖的优雅感觉。

在本文中,我们的实验要完成两个工作,一个是加法,一个是累计调用加法的次数,最普通的Python程序可以这么写:

 def validate(a, b):
if ((isinstance(a, int) or isinstance(a, float))
and (isinstance(b, int) or isinstance(b, float))):
return True
return False def add(a, b):
if validate(a, b):
return a + b
return "Invalid." count = 0 def counter(func):
global count
count = count + 1
return (count, func) print(counter(add(1, 2)))
print(counter(add(1, 3)))
print(counter(add('', 4)))
print(counter(add(1, 5)))
print(counter(add(1, 6)))

结果:

>> long@happytime:~/development/closure$ python3 test.py
>> (, )
>> (, )
>> (, 'Invalid.')
>> (, )
>> (, )

虽然可以正确显示结果,但是有如下几个不满意的地方:

  1. 全局变量的使用首先是不提倡的;
  2. 每次调用add都需要手动调用counter;
  3. add函数和validate函数耦合在一起,如果以后需要判断更多条件,会产生很多层的if-else的嵌套。

用闭包解决问题1:

 def validate(a, b):
if ((isinstance(a, int) or isinstance(a, float))
and (isinstance(b, int) or isinstance(b, float))):
return True
return False def add(a, b):
if validate(a, b):
return a + b
return "Invalid." def counter():
ct = 0 def do(func):
nonlocal ct
ct = ct + 1
return (ct, func)
return do ct = counter()
print(ct(add(1, 2)))
print(ct(add(1, 3)))
print(ct(add('', 4)))
print(ct(add(1, 5)))
print(ct(add(1, 6)))

结果:

>> long@happytime:~/development/closure$ python3 test1.py
>> (, )
>> (, )
>> (, 'Invalid.')
>> (, )
>> (, )

用装饰器进一步解决问题2:

 def validate(a, b):
if ((isinstance(a, int) or isinstance(a, float))
and (isinstance(b, int) or isinstance(b, float))):
return True
return False def counter(func):
ct = 0 def count(a, b):
nonlocal ct
ct = ct + 1
return (ct, func(a, b))
return count @counter
def add(a, b):
if validate(a, b):
return a + b
return "Invalid." print(add(1, 2))
print(add(1, 3))
print(add('', 4))
print(add(1, 5))
print(add(1, 6))

结果:

>> long@happytime:~/development/closure$ python3 test2.py
>> (1, 3)
>> (2, 4)
>> (3, 'Invalid.')
>> (4, 6)
>> (5, 7)

用装饰器进一步解决问题3:

 def validate(func):
def do(a, b):
if ((isinstance(a, int) or isinstance(a, float))
and (isinstance(b, int) or isinstance(b, float))):
return func(a, b)
return "Invalid."
return do def counter(func):
ct = 0 def count(a, b):
nonlocal ct
ct = ct + 1
return (ct, func(a, b))
return count @counter
@validate
def add(a, b):
return a + b print(add(1, 2))
print(add(1, 3))
print(add('', 4))
print(add(1, 5))
print(add(1, 6))

结果:

>> long@happytime:~/development/closure$ python3 test3.py
>> (1, 3)
>> (2, 4)
>> (3, 'Invalid.')
>> (4, 6)
>> (5, 7)

运用装饰器,可以在执行add的同时做很多事情,但耦合度很低,需要就加上装饰器,不需要就去掉。不过需要注意的是,多个装饰器的调用顺序是从下到上。所以@validate在@counter的下面。

python闭包与装饰器的更多相关文章

  1. python 闭包和装饰器

    python 闭包和装饰器 一.闭包闭包:外部函数FunOut()里面包含一个内部函数FunIn(),并且外部函数返回内部函数的对象FunIn,内部函数存在对外部函数的变量的引用.那么这个内部函数Fu ...

  2. 高逼格利器之Python闭包与装饰器

    生活在魔都的小明,终于攒够了首付,在魔都郊区买了一套房子:有一天,小明踩了狗屎,中了一注彩票,得到了20w,小明很是欢喜,于是想干脆用这20万来装修房子吧(decoration): 整个装修过程,小明 ...

  3. Python—闭包和装饰器

    闭包 定义:内部函数对外部函数变量的引用,则将该函数与用到的变量称为闭包. 闭包必须满足以下三个条件: 必须有一个内嵌函数. 内嵌函数必须引用外部函数中的变量. 外部函数返回值必须是内嵌函数的引用. ...

  4. Python 简明教程 --- 22,Python 闭包与装饰器

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 当你选择了一种语言,意味着你还选择了一组技术.一个社区. 目录 本节我们来介绍闭包与装饰器. 闭包与 ...

  5. Python闭包及装饰器

    Python闭包 先看一个例子: def outer(x): def inner(y): return x+y return innder add = outer(8) print add(6) 我们 ...

  6. python闭包以及装饰器

    通俗的定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).它只不过是个“内层”的函数,由一个名字(变量)来指代,而这个名字(变 ...

  7. python闭包和装饰器

    本文目录: 1. 闭包的解析和用法 2. 函数式装饰器 3. 类装饰器 一.闭包 闭包是一种函数,从形式上来说是函数内部定义(嵌套)函数,实现函数的扩展.在开发过程中,考虑到兼容性和耦合度问题,如果想 ...

  8. python闭包和装饰器(转)

    一.python闭包 1.内嵌函数 >>> def func1(): ... print ('func1 running...') ... def func2(): ... prin ...

  9. 详解Python闭包,装饰器及类装饰器

    在项目开发中,总会遇到在原代码的基础上添加额外的功能模块,原有的代码也许是很久以前所写,为了添加新功能的代码块,您一般还得重新熟悉源代码,稍微搞清楚一点它的逻辑,这无疑是一件特别头疼的事情.今天我们介 ...

随机推荐

  1. JS不用通过其他转换两个小数加减得到正确答案

    之前写过一篇文章js比较两个属于float类型的小数,都需要通过某种函数转换下,太麻烦了,比如: 减法:10.2345-0.01=10.2245,这是正确的答案,但是当你做加法的时候就变了 加法:10 ...

  2. sql 查询最近30分钟或者自定义时间数据

    ) FROM dual; 30分钟或者自定义

  3. 模拟赛1102d1

    炮(cannon)[题目描述]众所周知,双炮叠叠将是中国象棋中很厉害的一招必杀技.炮吃子时必须隔一个棋子跳吃,即俗称"炮打隔子". 炮跟炮显然不能在一起打起来,于是rly一天借来了 ...

  4. 用Mysqlbinlog备份BinLog文件

    默认情况下, mysqlbinlog读取二进制文件[BinLog]并以文本的方式呈现[text format].mysqlbinlog可以直接地从本地读取Log,也可以读取远程的Log[--read- ...

  5. [转]c++ vector 遍历方式

    挺有趣的,转来记录 随着C++11标准的出现,C++标准添加了许多有用的特性,C++代码的写法也有比较多的变化.   vector是经常要使用到的std组件,对于vector的遍历,本文罗列了若干种写 ...

  6. EventBus学习入门

    EventBus Features What makes greenrobot's EventBus unique, are its features: Simple yet powerful: Ev ...

  7. 关于v$datafile中system表空间的status值始终为system

    http://docs.oracle.com/cd/B19306_01/server.102/b14237/dynviews_1076.htm#REFRN30050 http://blog.itpub ...

  8. SQLServer系统监控

    http://blog.sina.com.cn/s/blog_519d269c0100gx09.html http://blog.csdn.net/qxlwuyuhui0801/article/det ...

  9. jQuery ajax同步的替换方法,使用 $.Deferred()对象

    function aa() { var defer = $.Deferred(); $.ajax({ url: "/Handler1.ashx", type: "post ...

  10. ACM训练计划建议(写给本校acmer,欢迎围观和指正)

    ACM训练计划建议 From:freecode#  Date:2015/5/20 前言: 老师要我们整理一份训练计划给下一届的学弟学妹们,整理出来了,费了不少笔墨,就也将它放到博客园上供大家参考. 菜 ...