谈谈我心中的 Python 烧脑系列之 Decorator

270 views
Skip to first unread message

李海珍

unread,
Jan 26, 2016, 9:11:40 AM1/26/16
to python-cn(华蟒用户组,CPyUG 邮件列表)
直到现在我也只是能明白比较简单的 Decorator,可能是我的脑回路比较短吧.
最近我感到费解的便是在看 Django 的 `permission_required` 这个 `decorator` 的代码时觉得很难下手.
我去看 Django 的源代码是我一个朋友想在 ModelAdmin 中的 Action 中使用 `permission_required`,结果不行
因为 `permission_required` 只能用在 view 函数中.

## `@` Decorator 语法
Decorator 从几年前我接触时,对我烧脑感觉就是,我无法知道他是做什么的,
只会文档让我用什么,我就用什么,比如最开始的 `@property`,`@classmethod`
很长一段时间我除了使用系统内置的这几个 Decorator 之外就没有尝试过其他的,更别谈自己写 Decorator 了.
老实来说,我在学校系统学习的是 Java,而 Java 也有这种 `@InjectView` 这种以 `@` 开头的用法,一开始
我先入为主的以为 Python 中的 Decorator 也类似于 Java 中的 注解,为此我还有些高兴,因为 Java 中的注解我是比较熟悉的.
这是我错误的第一步,后来我通过学习才感觉事实完全不是我想的那样的, Decorator 根本不是注解.而是一种函数嵌套调用的方便写法, 

```py
@decor1
def func1:pass
```
相当于 `deocor1(func1)`


## 烧脑的 wrap

有一次我发现很多的 `Decorator` 都有使用一个 `functools.wraps` 函数.

```py
def wraps(wrapped,assigned = WRAPPER_ASSIGNMENTS,updated = WRAPPER_UPDATES):
    return partial(update_wrapper, wrapped=wrapped, assigned=assigned,updated=updated)
```
然后我首先我费力的了解了 `partial` 其实是在通过设置预置的参数来特殊某一个函数以生成新的函数 .

很多时候我都会忘记`wraps` 是用来做什么的? 经常查询文档我发现,它其实是可有可无的东西,有更好,没有,一般情况下也不影响功能. 
`wraps` 主体在于 `update_wrapper` 这样的函数,其实很多时候也是比较费脑了,包装者与被包装者,我是这样来理解
`wrapper`,`wrapped`. 这让我想起"爱情公寓" 中陈美佳分不清,委托人和被委托人一样.
文档中对这个方法的说明是:"更新一个包装函数使它看起来像被包装的函数"
不过看到两人默认的参数值的时候,我仿佛明白了点什么:

```py

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
WRAPPER_UPDATES = ('__dict__',)
```
将被包装的函数的 `__module__`,`__name__`,`__doc__` 属性复制到 包装函数中去,
将被包装的函数 的`__dict__` 中的数据合并到 包装函数中去.
而要真正的理解这里为什么需要这样做,是需要明白下面的代码到底做了什么:

```
@decorator
def func1():pass
```

前面我已经理解了它是 `decorator(func1)` 
但是还有另一个隐含的结果我没有深入理解.

比如在下面的代码:

```py
// foo.py
def func1():pass
```
需要理解成,foo 模型有一个名为 `func1` 的标识符绑定到了`func1` 声明的函数体中.

```py
@decorator
def func1():pass
```

需要理解成下面的代码

```py
def func1():pass
func1 = decorator(func1)
```

很关键的一点是,`func1` 现在被重新赋值了,`func1` 这个标识符被绑定到了 `decorator(func1)` 的执行返回结果去了.


## 这么多的嵌套
当我在看 Django 的 `permission_required` 函数时,我大概已经掌握了上面我说的烧脑的点,
但是还是抵不住 `permission_required` 函数有众多层的嵌套啊.

```py
def permission_required(perm, login_url=None, raise_exception=False):
def check_perms(user):pass
return user_passes_test(check_perms,login_url=login_url)
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
    def decorator(view_func):
        @wraps(view_func, assigned=available_attrs(view_func))
        def _wrapped_view(request, *args, **kwargs):
            if test_func(request.user):
                return view_func(request, *args, **kwargs)
            return redirect_to_login(
                path, resolved_login_url, redirect_field_name)
        return _wrapped_view
    return decorator
```

函数套函数,函数传函数, 啊,让我静一静先.


首先我需要明白:

```py
@permission_required('polls.can_vote')
def my_index(request):pass
```

这样的代码,my_index 最后是绑定到哪一个函数去了?
首先是推算出 `permission_required('polls.can_vote')` 的调用结果
也就是: `user_pass_test` 的调用结果.
它的调用结果是返回 其内部定义的名为: `decorator` 函数.
也就是说 `permission_required('polls.can_vote')` 的调用结果为:
`deorator = permission_required('polls.can_vote')`
然后也就是说:
`my_index = decorator(my_index)`
而 `decorator` 的调用结果是 名为 `_wrapped_view` 这个函数
也就是说最后:

`my_index = _wrapped_view`
调用 `my_index` 就相当于调用 `__wrapped_view`
而原来的 `my_index` 所指向的函数体,就是由其中的`view_func` 闭包函数变量来指向.

到这里,我基本学会了,面对复杂的 `Decorator` 函数就是层层剥开它来理解他.







 



依云

unread,
Jan 26, 2016, 9:59:17 AM1/26/16
to pyth...@googlegroups.com
On Tue, Jan 26, 2016 at 02:11:15PM +0000, 李海珍 wrote:
> [...]
>
> 到这里,我基本学会了,面对复杂的 `Decorator` 函数就是层层剥开它来理解他.

不知道你有没有见过这种情况呢(这个例子是我杜撰的):

@route('/xxx')
@requires(param='abc', type=int)
@requires(param='def', type=str)
@optional(param='ghi')
@check_login
@may_mobile_redirect
@cache(key='yyy', expiration='2h')
def the_func(...):
...

:-D

--
Best regards,
lilydjwg

Linux Vim Python 我的博客:
http://lilydjwg.is-programmer.com/
--
A: Because it obfuscates the reading.
Q: Why is top posting so bad?

fy

unread,
Jan 26, 2016, 11:38:56 AM1/26/16
to python-cn
你这是滥用呀,这么多……



--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了 Google 网上论坛的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com
要向此群组发帖,请发送电子邮件至 pyth...@googlegroups.com
要查看更多选项,请访问 https://groups.google.com/d/optout

Shell Xu

unread,
Jan 26, 2016, 10:33:53 PM1/26/16
to CUPG
你弄明白了闭包,装饰器就是三分钟的事。
你弄明白了代码作用域包含和自由变量,闭包就是三分钟的事。

最近写书的时候就研究了作用域包含问题,所以大概知道是怎么递进的。

有的时候理解了高阶问题,再拿来研究实现真是非常爽快。
例如搞明白了偏序和全序集合,同序和拓扑排序问题,再来看C3算法。。。

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com
要发帖到此群组,请发送电子邮件至pyth...@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout



--
彼節者有間,而刀刃者無厚;以無厚入有間,恢恢乎其於游刃必有餘地矣。
blog: http://shell909090.org/blog/

peng yu

unread,
Jan 26, 2016, 10:50:41 PM1/26/16
to pyth...@googlegroups.com
ls在写什么书!

Shell Xu

unread,
Jan 26, 2016, 11:09:21 PM1/26/16
to CUPG
黑魔法入门和黑魔法防御。。。

shhgs

unread,
Jan 26, 2016, 11:25:02 PM1/26/16
to pyth...@googlegroups.com
decorator不难理解,难的是能用对地方。

上面这个例子我就觉得不错。这个the_func要执行的是一系列逻辑上相互独立,且又具有通用性的计算过程。在这种情况下,运用一连串的decorator犹如用shell的管道将多条命令串起来,可以说是非常的漂亮。

但是类似上面这样成熟的pattern并不是很多。

您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com

Shell Xu

unread,
Jan 26, 2016, 11:47:23 PM1/26/16
to CUPG
chain of responsibility模式。
关键是逻辑正交。即使是TCPIP这种很成熟的栈,也有ftp这种特例。。。

Ping Yang

unread,
Jan 27, 2016, 7:55:58 PM1/27/16
to pyth...@googlegroups.com
我们都是有生活的人...
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com

Coyote

unread,
Jan 27, 2016, 7:58:17 PM1/27/16
to python-cn(华蟒用户组,CPyUG 邮件列表)
2333 sh快出啊,看过你的keynote之后感觉分析问题很透彻。。很想看看你写的书。。。

黑魔法。。。什么鬼

在 2016年1月27日星期三 UTC+8下午12:09:21,shell909090写道:
黑魔法入门和黑魔法防御。。。

ls在写什么书!

要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+unsubscribe@googlegroups.com
要发帖到此群组,请发送电子邮件至python-cn@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout



--
彼節者有間,而刀刃者無厚;以無厚入有間,恢恢乎其於游刃必有餘地矣。
blog: http://shell909090.org/blog/

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+unsubscribe@googlegroups.com
要发帖到此群组,请发送电子邮件至python-cn@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+unsubscribe@googlegroups.com
要发帖到此群组,请发送电子邮件至python-cn@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout

GameXG

unread,
Jan 27, 2016, 10:27:56 PM1/27/16
to python-cn(华蟒用户组,CPyUG 邮件列表)
之前专门学习过,现在又忘的差不多了。
不过需要写的时候再查之前的记录吧。

Coyote <chenc...@gmail.com>于2016年1月28日周四 上午8:58写道:
黑魔法入门和黑魔法防御。。。

ls在写什么书!

要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com
要发帖到此群组,请发送电子邮件至pyth...@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout



--
彼節者有間,而刀刃者無厚;以無厚入有間,恢恢乎其於游刃必有餘地矣。
blog: http://shell909090.org/blog/

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com
要发帖到此群组,请发送电子邮件至pyth...@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com
要发帖到此群组,请发送电子邮件至pyth...@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout



--
彼節者有間,而刀刃者無厚;以無厚入有間,恢恢乎其於游刃必有餘地矣。
blog: http://shell909090.org/blog/

--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。

Zoom.Quiet

unread,
Jan 27, 2016, 10:29:17 PM1/27/16
to CPyUG~华蠎用户组
忘记的就是不重要的
不知道就是不必要的
现实往往不是这样的
Life's Pathetic, Let's Pythonic! 人生苦短, Python是岸!
俺: http://zoomquiet.io
授: http://creativecommons.org/licenses/by-sa/2.5/cn/
怒: 冗余不做,日子甭过!备份不做,十恶不赦!
KM keep growing environment culture which promoting organization be learnning!

victor lee

unread,
Jan 28, 2016, 4:21:30 AM1/28/16
to 华蟒
逻辑意义上来说就是作用域和闭包的问题。这两个东西让人不爽的绝对不在decorator而在lambada。
举例来说(From http://stackoverflow.com/questions/2295290/what-do-lambda-function-closures-capture-in-python):
adders= [0,1,2,3]
for i in [0,1,2,3]:
   adders[i]=lambda a: i+a

print adders[1](3)
楼主可以猜猜看输出多少。



要学会如何不成为一个愤青。<-此句为自言自语。
Vic the geek ,
理性主义、神秘主义、泛神论、人文主义者,道教信奉者,苏格拉底及柏拉图支持者。二元论支持者。
君子泰而不娇;君子举重若轻。

您收到此邮件是因为您订阅了 Google 网上论坛的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com

Shell Xu

unread,
Jan 28, 2016, 4:25:14 AM1/28/16
to CUPG
6吧。我没跑,猜的。

victor lee

unread,
Jan 28, 2016, 4:33:00 AM1/28/16
to 华蟒
壳大你上还会错吗……
对,6。
曾经为这种问题付出了将近50小时的debug time,当然不是这个代码。

要学会如何不成为一个愤青。<-此句为自言自语。
Vic the geek ,
理性主义、神秘主义、泛神论、人文主义者,道教信奉者,苏格拉底及柏拉图支持者。二元论支持者。
君子泰而不娇;君子举重若轻。

Lei Zhang

unread,
Jan 28, 2016, 4:33:46 AM1/28/16
to pyth...@googlegroups.com
adders= [0,1,2,3]

for i in [0,1,2,3]:
    def foo(a):
        return i+a
    adders[i]=foo

print adders[1](3)


还是作用域的问题啊,和 lambda 也没有哈关系。

2016-01-28 17:21 GMT+08:00 victor lee <victor...@gmail.com>:



--
Jeffrey Zhang
twitter/weibo: @jeffrey4l

fy

unread,
Jan 28, 2016, 4:41:25 AM1/28/16
to python-cn
这种代码我感觉一方面感觉蛋疼,另一方面对解释起来说也有些无奈吧。。



< Lei Zhang> 2016-01-28 17:33:44 wrote:
adders= [0,1,2,3]

for i in [0,1,2,3]:
    def foo(a):
        return i+a
    adders[i]=foo

print adders[1](3)


还是作用域的问题啊,和 lambda 也没有哈关系。
2016-01-28 17:21 GMT+08:00 victor lee <victor...@gmail.com>:
逻辑意义上来说就是作用域和闭包的问题。这两个东西让人不爽的绝对不在decorator而在lambada。
举例来说(From http://stackoverflow.com/questions/2295290/what-do-lambda-function-closures-capture-in-python):
adders=[0,1,2,3]for i in[0,1,2,3]:   adders[i]=lambda a: i+aprint adders[1](3)
楼主可以猜猜看输出多少。





--

Jeffrey Zhang
twitter/weibo: @jeffrey4l

Shell Xu

unread,
Jan 28, 2016, 4:52:51 AM1/28/16
to CUPG
这种代码不应当被写出来。
但是不知道哪里有坑,就不知道如何避开坑。

victor lee

unread,
Jan 28, 2016, 4:58:06 AM1/28/16
to 华蟒
嗯……这个实现对于程序员来说多少有点反直觉。看Haskell·:
Prelude>let fs = [(\n ->; i + n) | i <;- [0..9]]
Prelude>[f(4) | f <;- fs]
[4,5,6,7,8,9,10,11,12,13]
和python:
>>>fs = [lambda n:i+n for i in range(9)]
>>>[f(4) for f in fs]
[13,13,13,13,13,13,13,13,13,13]

————————————
给一个可能的实际应用会造成这种情况的例子:

register_a_hook(callback=lambda *args: self.calc(*args,self.nowState))
好了,这个self.nowState是callback定义时的还是callback调用时的要猜一下了。

whycrying

unread,
Jan 28, 2016, 5:23:52 AM1/28/16
to pyth...@googlegroups.com
我觉得 Flask 的作者 Armin 就是这方面的“行家”,比如:

http://click.pocoo.org/

个人不太喜欢 decorator 满天飞的代码。。。


--
邮件来自: `CPyUG`华蟒用户组(中文Python技术邮件列表)
规则: http://code.google.com/p/cpyug/wiki/PythonCn
详情: http://code.google.com/p/cpyug/wiki/CpyUg
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
---
您收到此邮件是因为您订阅了 Google 网上论坛的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com
要向此群组发帖,请发送电子邮件至 pyth...@googlegroups.com
要查看更多选项,请访问 https://groups.google.com/d/optout

shhgs

unread,
Jan 28, 2016, 10:27:56 AM1/28/16
to pyth...@googlegroups.com
都是lazy evaluation的错。

Shell Xu

unread,
Jan 28, 2016, 10:12:32 PM1/28/16
to CUPG
你可能没看过web.py的源码。。。

您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com

要发帖到此群组,请发送电子邮件至pyth...@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout

李海珍

unread,
Jan 29, 2016, 5:52:24 AM1/29/16
to pyth...@googlegroups.com
哈哈,这个问题我清楚,JavaScript 也是这个样子的了,在循环中使用闭包得小心, 最近我发现  Swift 就没有这方面的坑

victor lee <victor...@gmail.com>于2016年1月28日周四 下午5:21写道:

Shell Xu

unread,
Jan 29, 2016, 8:46:18 AM1/29/16
to CUPG
这个问题的核心是作用域,另外和闭包的细节也有关系。具体来说就是闭包在传递对象时,究竟是传递值还是传递环境。

victor lee

unread,
Jan 29, 2016, 9:07:37 PM1/29/16
to 华蟒
壳大正解。其实这本应该是一通百通的问题,其根本就是python解释器对于变量作用域的实现,其实官网有说明,不过初学者一般不看(或者看不懂)……
>>>哈哈,这个问题我清楚,JavaScript 也是这个样子的了,在循环中使用闭包得小心
这就是完全的误解了。使用闭包要小心的绝对不止在循环当中,比如我最后提出的例子:
registHook(callback=lambda *args,**kwargs:
doSomething(state=self.nowState,*args,**kwargs))
虽然这个代码本身就有二义性,按照游侠军规应该直接重写,但不得不说也算是很常见的写法——而这儿写多半是想把nowState当做callback定义的时候的nowState传递进去的,然而实际上这段代码state最终获得的是调用时的nowState。
>>>最近我发现 Swift 就没有这方面的坑
严格来说这不算坑,上面有大大提到了,这某种意义上属于lazy
evaluation,属于一定的语言哲学范畴。如果只是一个坑的话以Python这大刀阔斧的修整力度早应该消失在3里面了。
问题是Guido老人家不认为是坑嗯。

isdown Sun

unread,
Jan 29, 2016, 9:22:42 PM1/29/16
to pyth...@googlegroups.com
5 分钟看懂作用域 http://sunisdown.me/2014/05/16/python_legh.html 

victor lee <victor...@gmail.com>于2016年1月30日周六 上午10:07写道:

GameXG

unread,
Jan 30, 2016, 12:54:01 AM1/30/16
to pyth...@googlegroups.com
go 下可以这样做:
func main(){
    for i:=0;i<10;i++{
        i:=i   # 声明一个变量 i ,值为i
        f:=func(){return i}
    }
}

python 下没有块级变量下面就会失败。
>>> adders= [0,1,2,3]
>>> for i in [0,1,2,3]:
li=i  # 无效
def foo(a):
return li+a
adders[i]=foo
>>> adders[1](3)
6
>>> adders[0](3)
6

需要再增加一个函数。
>>> adders= [0,1,2,3]
>>> for i in [0,1,2,3]:
def tem():
   li=i
   def foo(a):
    return li+a
   adders[i]=foo
tem()
>>> adders[1](3)
4
>>> adders[0](3)
3
>>> 

不过这种坑很少被碰到。


isdown Sun <isdow...@gmail.com>于2016年1月30日周六 上午10:22写道:

依云

unread,
Jan 30, 2016, 9:46:16 AM1/30/16
to pyth...@googlegroups.com
On Sat, Jan 30, 2016 at 05:53:34AM +0000, GameXG wrote:
> go 下可以这样做:
> func main(){
> for i:=0;i<10;i++{
> i:=i # 声明一个变量 i ,值为i
> f:=func(){return i}
> }
> }

这种情况在 JavaScript 里遇到,我都是直接把 i 作为函数参数传进去的。
Python 里还没遇到这种需求。

peng yu

unread,
Feb 2, 2016, 3:27:21 AM2/2/16
to pyth...@googlegroups.com
这样就可以了吧。

adders= [0,1,2,3]
for i in [0,1,2,3]:
   adders[i]=lambda a, i=i: i+a

Shell Xu

unread,
Feb 2, 2016, 4:07:51 AM2/2/16
to CUPG
adders = [(lambda i: lambda a: i+a) (i) for i in range(0, 4)]
aka
adders = map(lambda i: lambda a: i+a, range(0, 4))

[(lambda i: lambda a: i+a) (i) for i in range(0, 4)][1](3)
Q.E.D

您收到此邮件是因为您订阅了Google网上论坛上的“python-cn(华蟒用户组,CPyUG 邮件列表)”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到python-cn+...@googlegroups.com

要发帖到此群组,请发送电子邮件至pyth...@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout

victor lee

unread,
Feb 3, 2016, 6:53:20 AM2/3/16
to 华蟒
强行lambda两次构造闭包当然是没问题了……

Jeffrey Zhang

unread,
Feb 3, 2016, 7:56:56 AM2/3/16
to pyth...@googlegroups.com
这东西感觉还是 JavaScript 里用的多。Python 感觉很少用到。。

Shell Xu

unread,
Feb 3, 2016, 8:36:50 AM2/3/16
to CUPG
很正常。lambda对可读性是毁灭性的。

lee Alexander

unread,
Feb 22, 2016, 1:17:43 AM2/22/16
to pyth...@googlegroups.com
其实正确的换行就可以解决lambda的可读性问题, 但是很多人都为了提高big写成一行, 并以此为荣

Shell Xu

unread,
Feb 22, 2016, 2:10:01 AM2/22/16
to CUPG
例如这个样子?


Y = lambda f: (
        lambda g: g(g))(
        lambda h: (
            lambda x: f(h(h))(x)))
print Y(lambda h: (
            lambda n: (
                1 if n < 2 else n * h(n-1))))(
        10)

lee Alexander

unread,
Feb 22, 2016, 6:00:14 AM2/22/16
to pyth...@googlegroups.com
😂, 我们还是来聊聊今天的天气吧

woosley. xu.

unread,
Feb 22, 2016, 10:29:12 PM2/22/16
to pyth...@googlegroups.com
这玩意是传说中的闭包(Late Binding Closures)啊,
这里有解释: http://docs.python-guide.org/en/latest/writing/gotchas/#late-binding-closures
woosley.xu.    http://twitter.com/redicaps


Reply all
Reply to author
Forward
0 new messages