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中的闭包原理
要了解清楚js中的闭包制机,那么得先了解全局执行环境.块级执行环境.函数执行环境.变量对象.环境栈.作用域链.摧毁执行环境. 全局执行环境 全局执行环境指的是最外层的执行环境.在web中全局执行环境被 ...
- 从发布订阅模式到redux(一)
最近在学习的过程中,学习了一些关于redux的一些知识,学之前用redux,虽然会用但是实现的原理就不是特别清楚,天天沉迷于搬砖 总是这木搬砖也不是个事啊,就准备开始深入了解一些原理性的东西 首先在看 ...
- Mysql LIMIT 分页
格式: LIMIT index, size // index:从哪一行(第几条)开始查,size:多少条 分页: LIMIT (currentPage-1)*pageSize, pageSiz ...
- linux连接数过多,导致ping包丢包的问题解析
1.首先要明确,无论是tcp, udp, raw等这些都要占用socket, 那么就涉及到连接数的问题. 所以,linux连接数的问题,不仅仅是tcp连接数. 2.查看当前系统中所有的socket 连 ...
- MySQL 横向表分区之RANGE分区小结
MySQL 横向表分区之RANGE分区小结 by:授客 QQ:1033553122 目录 简介 1 RANGE分区 1 创建分区表 1 查看表分区 2 新增表分区 2 新增数据 3 分区表查询 3 删 ...
- react 的双向数据绑定
学习过angular和vue的人都知道,它俩在实现双向数据绑定都是有一个专门的内置指令ngModel和v-model 但是在react中没有这些. 所以我们在react中想要实现双向数据绑定要调用一个 ...
- Jmeter和Loadrunner的异同
1.jmeter的架构跟loadrunner原理一样,都是通过中间代理,监控&收集并发客户端发现的指令,把他们生成脚本,再发送到应用服务器,再监控服务器反馈的结果的一个过程. 2.分布式中间代 ...
- Python 魔法方法简介
1.什么是魔法方法? 魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一 ...
- win7文件搜索技巧
重要说明 (1)搜索的字符串是大小写不敏感的 (2)字符串带双引号与不带双引号是有区别的 如:hello,搜索包含hello单词开头的文件或目录,名为“aa_HELLOcc...”.“cc-Hel ...
- MyBatis笔记----mybatis分页
mybatis版本3.4以下 结构 spring-mvc.xml <?xml version="1.0" encoding="UTF-8"?> &l ...