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.不能修改被装饰的函数的源代码 ...
随机推荐
- intellij error updating changes svn解决办法
乌龟检出的svn版本为1.8,而1.8在IntelliJ 上跑起来貌似有问题, 经过多次尝试,当Format改为1.7后,问题被解决.
- Fetch使用
Fetch API 提供了一个获取资源的接口(包括跨域请求).任何使用 过 XMLHttpRequest 的人都能轻松上手,但新的API提供了更强大和 灵活的功能集. 概念和用法 Fetch 提供了对 ...
- 一次断电引发的svn数据库故障
作者:朱金灿 来源:http://blog.csdn.net/clever101 昨天办公室停电了.然后今天更新svn数据库时出现一个不能读取文件:End of file found的错误,具体如下图 ...
- java排序算法之希尔排序
希尔排序是冲破二次时间屏障的第一批算法之一. 它是通过比较相距一定间隔的元素来工作,各趟比较所用的距离随着算法的进行而减小,直到最后一趟(比较相邻元素)为止.因此希尔排序也叫缩减增量排序. 希尔排序使 ...
- Python基于Python实现批量上传文件或目录到不同的Linux服务器
基于Python实现批量上传文件或目录到不同的Linux服务器 by:授客 QQ:1033553122 实现功能 1 测试环境 1 使用方法 1 1. 编辑配置文件conf/rootpath_fo ...
- C# RichTextBox 制作文本编辑器
本文利用一个简单的小例子[文本编辑器],讲解RichTextBox的用法,仅供学习分享使用,如有不足之处,还请指正. Windows窗体中的RichTextBox控件用于显示,输入和操作格式化的文本, ...
- git 入门教程之远程仓库
远程仓库 如果说本地仓库已经足够个人进行版本控制了,那么远程仓库则使多人合作开发成为可能. 如果你只是打算自己使用git,你的工作内容不需要发布给其他人看,那就用不到远程仓库的概念. git 是分布式 ...
- (网页)sweetalert api 中文开发文档和手册,项目放弃alert
弹框json的特别好使. sweetalert 示例 基本信息弹窗swal("这是一条信息!") 标题与文本的信息弹窗swal("这是一条信息!", " ...
- 使用Visual Studio Team Services进行压力和性能测试(一)——创建基础的URL压力测试
使用Visual Studio Team Services进行压力和性能测试(一)--创建基础的URL压力测试 概述 压力测试使应用程序更加健壮,并审核在用户负载下的行为,这样我们可以在当前的基础设施 ...
- Python 魔法方法简介
1.什么是魔法方法? 魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一 ...