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.不能修改被装饰的函数的源代码 ...
随机推荐
- js 元素大小缩放实例
元素大小缩放是一套连贯事件,按下鼠标不放,拖动鼠标 然后松开. 按下鼠标事件 当按下鼠标时,记录元素大小.鼠标按下的位置.状态位. 拖动鼠标事件 当鼠标拖动时,计算元素调用后的大小. 元素调整后大小 ...
- CSS3使用transition属性实现过渡效果
transition属性目的是让css的一些属性(如background)的以平滑过渡的效果出现.它是一个合并属性,是由以下四个属性组合而成: transition-property:设置应用过渡的C ...
- angular 分页插件的使用
html: <pagination total-items="totalItems" ng-model="currentPage" items-per-p ...
- vue从入门到进阶:计算属性computed与侦听器watch(三)
计算属性computed 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的.在模板中放入太多的逻辑会让模板过重且难以维护.例如: <div id="example" ...
- Vue+axios统一接口管理
通过axios请求接口已经很简单了,但最近在做一个vue项目,想着把axios请求再封装一下,这样api就可以只在一处配置成方法,在使用的时候直接调用这个方法. 但咱们不用每个接口都定义成一个啰嗦的a ...
- 2018-10-08 Java源码英翻中进展-内测上线
创建了一个子域名: http://translate.codeinchinese.com/ 欢迎试用, 如有建议/发现问题欢迎在此拍砖: program-in-chinese/code_transla ...
- T研究:国内云BPM市场规模尚小,预计2018年仅为3.29亿元
文章摘要:T研究发现,目前国内云BPM市场规模不高,预计今年为3.29亿元,不过其增速稳定,未来发展仍可期. BPM?什么鬼?反正作为“菊外人”的小编是第一次听说. 其实,对于这个词,不光是小编,国内 ...
- 系统调用fork()在powerpc上的源码分析
总结一句话:系统调用的本质,通过sc指令触发异常,完成用户态到内核的转换. 展开一些:应用程序调用fork(),fork()是一个glibc函数,该函数的最底层调用sc指令,触发cpu异常,从而完成从 ...
- leetcode-9.回文数(水仙花数)
leetcode-9.回文数(水仙花数) 题意:给定整数,判断是否是水仙花数(回文数),返回判断结果 算法: 1.判断负数, 如果是负数直接返回false 2.将整数逐位拆解,用数组存储 3.遍历数组 ...
- Floyd算法_MATLAB
%求图中任意两点之间的最短距离与最短路径 %floyd算法通用程序,输入a为赋权邻接矩阵 %输出为距离矩阵D,和最短路径矩阵path function D=floyd(a) n=size(a,);%行 ...