15 python 初学(闭包,函数装饰器)
这一部分很重要,一定要透彻理解。可参考大神博客:
http://www.cnblogs.com/yuanchenqi/articles/5830025.html
闭包:
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数被认为是闭包。
闭包 = 函数块 + 定义函数时的环境
inner 是内部函数,对 x 进行引用,内部函数 inner 就是一个闭包
!!!当闭包执行完后,仍然能够保持住当前的运行环境。比如说,如果你希望函数的每次执行结果,都是基于这个函数上次的运行结果。
# 个人理解:下面的 inner()函数不是一个闭包函数,因为他并没有使用 outer 中的外部变量。
# 不理解的一点:在外部直接调用 inner()函数不可行 (是因为找不到),但是执行outer(),将 inner 作为返回值给f,f在外部就可以执行。这又是因为什么呢???
# ------------闭包有一个属性__closure__。 如果 inner 函数没有使用外部变量,那就不属于闭包的范畴。 f.__closure__返回为None。
def outer():
x = 10
def inner():
return 5
return inner f = outer() # f.__closure__返回为None。不是闭包
print(f())
# 下面的 inner()函数是一个闭包函数,因为 inner 函数和外部环境变量 x 结合在了一起。
def outer():
x = 10
def inner():
print(x)
return 5 return inner # f 其实就是 inner,但此处仍然可以执行inner,就是因为inner使用了外部变量 x,在return inner的时候把x也一起捆绑给了他,让他使用。但是如果单独调用inner函数就会报错。
f = outer() # f.__closure__返回为:(<cell at 0x000000FB7467D768: int object at 0x00007FFB0FD7B470>,) print(f())
闭包应用:装饰器
闭包举例:棋盘。参考上面博客链接
开放封闭原则:
封闭原则:代码写好后不允许再进行修改
开放原则:在不修改代码的条件下可以进行功能扩展
装饰器:
# 需求:打印出每个函数执行时间 # 这样写的话,每个需要打印执行时间的函数都要写一遍相同的代码,代码重复。
def foo():
start = time.time()
print('foo....')
end = time.time()
print('spend: %s' %(end - start)) foo() # 改进方法1 :抽出相同的代码,写成函数print_time,将 foo 函数作为参数传入
# 问题:在这种情况下,我不能调用函数本身去实现打印时间了,而是要通过print_time函数。
# 这样如果其它地方之前是调用了这个函数来打印时间,现在改进了之后,就都要改一遍调用方式,很麻烦
def foo():
print('foo....')
time.sleep(2) def print_time(f):
start = time.time()
f()
end = time.time()
print('spend: %s' % (end - start)) print_time(foo) # 改进方法2:在 print_time 函数内定义一个内部函数 inner(),将 print_time 返回这个内部函数,重新赋值给函数变量 foo。
# 这样通过直接调用 foo()就可以实现打印时间的功能了。
# 改进方法3:更加高级一点的方法,使用装饰器(其实我觉得每次写 foo = print_time(foo) 也是一个很浪费时间的重复工作,装饰器可以解决)
# 通过给一个函数使用装饰器,每次就可以直接通过调用函数来实现打印时间的功能了。 def print_time(f):
def inner():
start = time.time()
f()
end = time.time()
print('spend: %s' % (end - start)) return inner @print_time # 等价于语句:foo = print_time(foo)
def foo():
print('foo....')
time.sleep(2) # 改进方法2 部分
# foo = print_time(foo) foo()
带参数的被装饰函数:即 foo 是一个有参数的函数,那么如何写这个装饰器呢?
由浅入深,从简单的两个参数到不定长参数。
两个参数实现举例:需要注意的地方
1. inner(a, b)函数的参数要和foo(a, b)函数的参数保持一致。a, b 参数会自动对应 foo(a, b)的参数
2. inner(a, b)函数内部一定要调用实现 f(a,b)函数。
3. (我自己的理解与想象,未证实)foo 函数 使用装饰器 @print_time 时,因为 print_time 函数定义的有参数 f,因此就会自动帮我们将 foo 函数变量作为参数传入。
def print_time(f):
def inner(a, b):
start = time.time()
f(a, b)
end = time.time()
print('spend: %s' % (end - start)) return inner @print_time # 等价于语句:foo = print_time(foo)
def foo(a, b):
print(a + b)
time.sleep(2) foo(2,3) #
# spend: 2.0001039505004883
不定长参数:
import time def print_time(f):
def inner(*args, **kwargs):
start = time.time()
f(*args, **kwargs)
end = time.time()
print('spend: %s' % (end - start)) return inner @print_time # 等价于语句:foo = print_time(foo)
def foo(*args, **kwargs):
sum = 0
for i in args:
sum += i
print(sum)
time.sleep(2) foo(2, 3, 4, 5)
带参数的装饰器:
被装饰函数可以带参数,那么装饰器可以带参数吗?答案是肯定的。
看一下实现举例(函数直接复制的):
import time def time_logger(flag=0):
def show_time(func):
def wrapper(*args, **kwargs):
start_time = time.time() func(*args, **kwargs) end_time = time.time() print('spend %s' % (end_time - start_time)) if flag:
print('将这个操作的时间记录到日志中') return wrapper return show_time @time_logger(3)
def add(*args, **kwargs):
time.sleep(1) sum = 0 for i in args:
sum += i print(sum) add(2, 7, 5)
在上面这个函数中,装饰器变为了 @time_logger(3),他做的主要工作有哪些呢,即他实现了一个什么功能呢?
1. 执行time_logger(3),得到闭包变量 show_time,里面保存环境变量 flag。
2. 执行 @show_time,相当于实现语句 add = show_time(add)。接下来的逻辑同上
(自己的理解,期待指正):之所以先执行time_logger(3),而不是执行@time_logger(3),是因为判断出 time_logger 函数里面并没有将函数 add 传入进去,而是传入了 3。因此就先执行了time_logger(3),并返回了闭包变量 show_time。
接下里试着执行 @show_time,发现此处没有传参数,但是 show_time 函数定义中却有一个参数 f,因此就会将函数 add 作为实参传给 f。这样就执行了 @show_time
???是不是将 函数add 传入后就是开始执行了装饰器语句 @show_time
等我理解的更深入了会再修改,目前的理解就是这样。
15 python 初学(闭包,函数装饰器)的更多相关文章
- Python作用域-->闭包函数-->装饰器
1.作用域: 在python中,作用域分为两种:全局作用域和局部作用域. 全局作用域是定义在文件级别的变量,函数名.而局部作用域,则是定义函数内部. 关于作用域,我要理解两点:a.在全局不能访问到局部 ...
- Python中利用函数装饰器实现备忘功能
Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下 " ...
- Python函数编程——闭包和装饰器
Python函数编程--闭包和装饰器 一.闭包 关于闭包,即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数).而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量.参数.当其中一个 ...
- 【Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数】
一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(Firs ...
- python之闭包与装饰器
python闭包与装饰器 闭包 在函数内部定义的函数包含对外部的作用域,而不是全局作用域名字的引用,这样的函数叫做闭包函数. 示例: #-------------------------------- ...
- Python之闭包and装饰器
闭包和装饰器是Python中非常重要的一种语法格式,在日常工作中应用非常广泛. 首先,我先为大家简单的介绍一下闭包的概念. 闭包:闭包是在函数嵌套的基础上,内层函数使用到外层函数的变量,且外层函数返回 ...
- Python中的@函数装饰器到底是什么?
在解释@函数装饰器之前,先说一下,类中的类方法和静态方法. 在Python中完全支持定义类方法.静态方法.这两种方法很相似,Python它们都使用类来调用(ps:用对象调用也可以). 区别在于:Pyt ...
- python语法基础-函数-装饰器-长期维护
######################################################### # 装饰器 # 装饰器非常重要,面试Python的公司必问, # 原则:开放封闭原则 ...
- python 修改的函数装饰器
把好的代码记录下来 方便以后学习 修改的函数参数装饰器 from functools import wraps import time import logging def warn(timeout) ...
- python二 总结--函数-- 装饰器
装饰器是什么? 有什么用? 为什么要用? 真的有用吗? 1.装饰器: 装饰器: 定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能. 原则:1.不能修改被装饰的函数的源代码 ...
随机推荐
- HTML基础总结
HTML细化知识点总结 1.h1-h6标签 都是标题标签,定义一段话的标题,h1最大,依次递减,h6最小 标题标签的作用:让文本加粗显示 2. 段落标签:p标签 用来显示一段文本(图片),它会忽略源代 ...
- [总结]WEB前端常用命令
webpack等工具操作 自动创建package.json文件:npm init 如何根据package.json来自动安装包:npm install npm具体安装某个组件:npm install ...
- JavaScript面向对象编程指南(六) 继承
第6章 继承 6.1 原型链 6.1.1原型链示例 原型链法:Child.prototype=new Parent(); <script> function Shape(){ this.n ...
- UoW中修改VIM的配色方案
在WIN10中提供Bash on Ubuntu on Windows,即在win中提供一个Ubuntu子系统,可以使用bash.该系统中自带的VIM的配色方案colorscheme为默认的,不怎么好, ...
- Android 弹性布局 FlexboxLayout了解一下
原文链接:https://mp.weixin.qq.com/s/Mi3cK7xujmEMI_rc51-r4g RelativeLayout.LinearLayout等常用布局相信大家早已耳熟能详,今天 ...
- 「Android」GreenDao
译文 版本:greenDAO 3.2.2 官网:http://greenrobot.org/greendao/ GitHub:https://github.com/greenrobot/greenDA ...
- WPF:完美自定义MeaagseBox 动画 反弹 背景模糊 扁平化
不知道为什么,WPF的MeaageBox的风格还停留在Win 2000的风格... 很久前就想自己封装一个MessageBox出来,但是都只是简单的封装,不怎么具有通用性.这次终于搞完了. 使用方法和 ...
- 制作OTA升级包
OTA 软件包工具 本文地址http://wossoneri.github.io/2018/09/21/%5BAndroid%5D%5BFramework%5Dcreate-ota-update-zi ...
- PyCharm 使用Github管理Django项目
不管是对于教程代码免费分享的需要,还是项目开发过程中的版本管理,Github都是我们首选的开源代码仓库,如果你没有私有仓库,并且不用保护代码,那么将项目上传到Github上是最佳的选择. 关于如何使用 ...
- 分布式:Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)
互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...