Python中late-binding-closures
2018-01-03 @望京
示例1
>>> b = []
>>> for i in range(5):
... b.append(lambda :i)
...
>>> for j in b:
... print j()
...
4
4
4
4
4
>>> for m in b:
... print type(m),m
...
<type 'function'> <function <lambda> at 0x7fe4aae708c0>
<type 'function'> <function <lambda> at 0x7fe4aae70938>
<type 'function'> <function <lambda> at 0x7fe4aae709b0>
<type 'function'> <function <lambda> at 0x7fe4aae70b18>
<type 'function'> <function <lambda> at 0x7fe4aae70b90>
>>>
>>>
为什么不是输出 0~4?
Closures in Python are late-binding,
meaning that each lambda function in the list will only evaluate the variable i when invoked,
and not when defined. That's why all functions return the same value, i.e. the last value of ì (which is 4).
late-binding-closures in Python http://docs.python-guide.org/en/latest/writing/gotchas/#late-binding-closures
怎么修改使之输出 0~4? b.append(lambda i=i:i)
>>> b = []
>>> for i in range(5):
... b.append(lambda i=i:i)
...
>>> for j in b:
... print j()
...
0
1
2
3
4
>>>
或者使用 functools.partial :
>>> b = []
>>> for i in range(5):
... from functools import partial
... b.append(partial(lambda x:x, i))
...
>>> for j in b:
... print j()
...
0
1
2
3
4
>>>
lambda补充
>>> foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
>>>
>>> print filter(lambda x: x % 3 == 0, foo) # 过滤
[18, 9, 24, 12, 27]
>>>
>>> print map(lambda x: x * 2 + 10, foo) # map
[14, 46, 28, 54, 44, 58, 26, 34, 64]
>>>
>>> print reduce(lambda x, y: x + y, foo) # 求和
139
>>>
示例2
>>> def func(arg=[]):
... arg.append(1)
... print arg
...
>>> func()
[1]
>>> func()
[1, 1]
>>>
修改1:在函数调用的时候传入参数
>>> def func(arg=[]):
... arg.append(1)
... print arg
...
>>> func([])
[1]
>>> func([])
[1]
>>>
修改2:默认参数改为 None (更安全的做法)
>>>
>>> def func(arg=None):
... if not arg:
... arg = []
... arg.append(1)
... print arg
...
>>>
>>> func()
[1]
>>> func()
[1]
>>>
示例3
>>>
>>> def func(x, l=[]):
... for i in range(x):
... l.append(i*i)
... print l
...
>>> func(2)
[0, 1]
>>> func(3)
[0, 1, 0, 1, 4]
>>>
2018-03-12 https://zhuanlan.zhihu.com/p/33376761
今天在地铁上看到公众号推荐这个文章,也是late-binding问题,再补充下:
def foo():
temp = [lambda x : i*x for i in range(4)]
return temp for bar in foo():
print(bar(2)) # 输出
6
6
6
6
其实可以改写成下面这样,这样就比较容易看出是闭包了:lambda本身是一个函数,调用了外面的变量 i
temp = []
for i in range(4):
temp.append(lambda x : i*x) for bar in temp:
print(bar(2))
解决方法1: [lambda x,i=i : i*x for i in range(4)]
def foo():
temp = [lambda x,i=i : i*x for i in range(4)]
return temp for bar in foo():
print(bar(2))
解决方法2:使用 functools.partial
from functools import partial
from operator import mul def foo():
temp = [partial(mul,i) for i in range(4)]
return temp for bar in foo():
print(bar(2))
解决方法3:把temp改成生成器
def foo():
temp = (lambda x : i*x for i in range(4))
return temp for bar in foo():
print(bar(2)) # 或者用 next() 方式调用
# bar = foo()
# print(next(bar)(2))
# print(next(bar)(2))
# print(next(bar)(2))
# print(next(bar)(2)) # 或者用 next() 方式调用
# bar = foo()
# print(bar.__next__()(2))
# print(bar.__next__()(2))
# print(bar.__next__()(2))
# print(bar.__next__()(2))
解决方法4:使用yield
def foo():
for i in range(4):
yield lambda x : i*x for bar in foo():
print(bar(2))
补充:
构造生成器的两种方式:
使用类似列表生成式的方式生成 (2*n + 1 for n in range(3, 11))
使用包含yield的函数来生成 如果计算过程比较简单,可以直接把列表生成式改成generator;
但是,如果计算过程比较复杂,就只能通过包含yield的函数来构造generator。
学无止境,戒骄戒躁。
Python中late-binding-closures的更多相关文章
- Python中的内置函数
2.1 Built-in Functions The Python interpreter has a number of functions built into it that are alway ...
- 可爱的 Python : Python中的函数式编程,第三部分
英文原文:Charming Python: Functional programming in Python, Part 3,翻译:开源中国 摘要: 作者David Mertz在其文章<可爱的 ...
- 可爱的 Python : Python中函数式编程,第二部分
英文原文:Charming Python: Functional programming in Python, Part 2,翻译:开源中国 摘要: 本专栏继续让David对Python中的函数式编 ...
- 使用RSA加密在Python中逆向shell
i春秋翻译小组-Neo(李皓伟) 使用RSA加密在Python中逆向shell 这是一个关于使用RSA加密编程逆向shell的python教程. 我想提一下,这篇文章更多的是关于理解shell中涉及的 ...
- python 中关于descriptor的一些知识问题
这个问题从早上日常扫segmentfault上问题开始 有个问题是 class C(object): @classmethod def m(): pass m()是类方法,调用代码如下: C.m() ...
- python之name binding
[python之name binding] 1. 名字 名字是对一个对象的称呼,一个对象可以只有一个名字,也可以没有名字或取多个名字.但对象自己却不知道有多少名字,叫什么,只有名字本身知道它所指向 ...
- python中的作用域与名称空间
python中的名称空间以及作用域分析 从Python解释器开始执行之后,就在内存中开辟一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征 ...
- Python中的__name__和__main__含义详解
1背景 在写Python代码和看Python代码时,我们常常可以看到这样的代码: ? 1 2 3 4 5 def main(): ...... if __name == "__m ...
- UnboundLocalError,探讨Python中的绑定
绑定 将python闭包之前,先梳理一下闭包中的绑定操作. 先看看2个相关的错误 NameError 和UnboundLocalError When a name is not found at al ...
- [转]Python中的str与unicode处理方法
早上被python的编码搞得抓耳挠腮,在搜资料的时候感觉这篇博文很不错,所以收藏在此. python2.x中处理中文,是一件头疼的事情.网上写这方面的文章,测次不齐,而且都会有点错误,所以在这里打算自 ...
随机推荐
- Java抽象类简单学习
使用抽象类应该注意的几个要点: 包含一个或者多个抽象方法的类必须被声明为抽象类. 将类声明为抽象类,不一定含有抽象方法. 通常认为,在抽象类中不应该包括具体方法,建议尽量将通用的域和方法放在超类中. ...
- [luogu1486][bzoj1503][NOI2004]郁闷的出纳员【平衡树treap】
题目描述 OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资 ...
- [模板] 动态dp
用途 对于某些树形dp(目前只会树上最大权独立集或者类似的),动态地修改点权,并询问修改后的dp值 做法(树剖版) 以最大权独立集为例 设$f[x][0/1]$表示x选不选,这棵子树的最大权独立集大小 ...
- gradle配置统一管理
配置全局参数 根目录build.gradle文件: 主要关注ext部分 // Top-level build file where you can add configuration options ...
- Go实战--golang中使用JWT(JSON Web Token)
http://blog.csdn.net/wangshubo1989/article/details/74529333 之前写过关于golang中如何使用cookie的博客: 实战–go中使用cook ...
- vue学习笔记(二)- 数据绑定、列表渲染、条件判断
vue的数据绑定和列表渲染的造轮子 GitHub:八至 作者:狐狸家的鱼 双向数据绑定 Vue中数据的双向绑定-v-model 数据->页面 页面->数据 适用:input.select. ...
- luogu2643 聪聪可可
题目链接 题意 其实转化之后的题意就是求出树上有多少条路径长度是3的倍数.求答案的时候只要将这个数字除以总路径数量就行了. 思路 考虑点分治.对于当前子树,分别求出出树中每个点到根的路径长度对\(3\ ...
- C#两个实体之间相同属性的映射
public static R Mapping<R, T>(T model) { R result = Activator.CreateInstance<R>(); forea ...
- ImageMagick - MAGICK_CODER_MODULE_PATH 测试结果, 很受伤
//通过查看 ImageMagick 源代码: http://code.metager.de/source/xref/ImageMagick/MagickCore/module.c#552 //首先会 ...
- Java 多线程篇
先举个例子 计算机的核心是CPU,它承担了计算机所有计算任务,可以把它理解为像一个工厂,时刻在运行. 假定工厂有一个电力系统,工厂有很多车间,一次只能供给一个车间使用,也就是说一个车间开工的时候,其他 ...