Python 闭包不支持修改 upvalue,有什么替代的解决方案?

2016-01-19 09:20:31 +08:00
 tabris17

如下代码:

def test_closure():
    x = 1
    def closure():
        x = 2
    closure()
    print x
test_closure()

x 仍然是 1

6226 次点击
所在节点    Python
67 条回复
ethego
2016-01-19 11:32:33 +08:00
@xuboying
```python
def test_closure():
----def closure():
--------closure.x = 2
----closure.x = 1
----closure()
----print b.x

test_closure()
```
print 有个小错误,改正了,你再试试
est
2016-01-19 11:34:44 +08:00
@tabris17 服。
ethego
2016-01-19 11:40:35 +08:00
@xuboying 不需要用一个类来封装,闭包函数也是动态创建的,函数也是对象
ethego
2016-01-19 11:47:12 +08:00
支持完整的闭包和不支持都没什么影响,能完成的功能一样可以完成,只是你心里舒服一些罢了,有人说 python 不纯,不是纯的函数式编程,卧槽,失望了,还不如 php 。我想说,你语言层面再纯,哪怕是 haskell 那样纯洁的小天使,编译成汇编机器码,一样是面向过程的,你追求的纯净的函数式编程只是镜花水月空中楼阁罢了。
BlackKey
2016-01-19 11:49:21 +08:00
PEP 227 里面解释了这个, Rebinding names in enclosing scopes 部分
简单来说就是他们不愿意(懒得)搞这个
xuboying
2016-01-19 11:52:59 +08:00
@ethego b.x 什么鬼?
print b.x
NameError: global name 'b' is not defined
ethego
2016-01-19 11:53:53 +08:00
@xuboying
```python
def test_closure():
----def closure():
--------closure.x = 2
----closure.x = 1
----closure()
----print closure.x

test_closure()
```
这里就一个 x ,你还不知道用哪个?
xuboying
2016-01-19 11:57:01 +08:00
@BlackKey 这个功能还真的是挺重要的,对于喜欢写递归的人来说,递归内的函数可以正确访问父函数的是保证逻辑正确的前提。 perl , js 都能很好的实现
如果因为不能处理好递归而被人要求去专用其他语言真的是和很伤心的事情
不过还好还是有 workaround 了
xuboying
2016-01-19 12:07:52 +08:00
@ethego 你这个写法也是对的!!!但是必须把函数放在最开头,而且这个变量从父函数变量变成子函数变量了,我不知道这样做是否妥当(感觉上逻辑变了),也不知道能不能解决需要访问父父函数变量的情况(虽然我从来没有这么尝试过)

def outer(s):
   if s == 4:
     return
   def inner():
     inner.x = inner.x * 2
   inner.x = s
   inner()
   print inner.x,
   outer(s+1)
   print inner.x,
if __name__ == "__main__":
   outer(1)


result: 2 4 6 6 4 2
BlackKey
2016-01-19 12:31:37 +08:00
@xuboying 我挺喜欢 Python 的,但有一点有时还是觉得挺烦的。他们经常喜欢让你接受他们认为好的方式,比如他们不提倡让你用匿名函数,结果 Python 匿名函数的就一直特别弱
xuboying
2016-01-19 12:36:43 +08:00
@BlackKey 众所周知, Perl 和 Python 的文化在很多方面是不同的。 PEP20 中提到了其中一点, There should be one-- and preferably only one --obvious way to do it.

然而却弄出了 Python 2 和 Python 3
clino
2016-01-19 12:41:23 +08:00
@jmc891205 我的理解不是屏蔽,而是认为声明了一个新的局部变量导致访问不到外面的那一个同名的
shyling
2016-01-19 13:13:28 +08:00
函数式还修改外部变量?函数自己的返回值呢?
ethego
2016-01-19 13:15:48 +08:00
@xuboying 正因为只选择一种最好的方式,所以才要彻底割裂 python 2 不好的地方。
musicx
2016-01-19 13:22:46 +08:00
我其实好奇是什么样的场景需要修改闭包外的值。。。而且要求不能用引用不能用将闭包返回值赋给原变量这两种方法。。。
tabris17
2016-01-19 13:35:09 +08:00
@shyling
@musicx

可以试试接触下 javascript ,回过头来你会发现不能修改 upvalue 才是很奇怪的设定
jmc891205
2016-01-19 13:36:56 +08:00
@clino 我所说的“屏蔽”就是你说的这个意思
xuboying
2016-01-19 14:20:40 +08:00
@ethego 如果 python 有这个自信,那么鉴别它做的好坏的方法是是否其他语言学习了他的精华,当你 porting python 到其他语言的时候没有很大的麻烦;如果大家都不像他,他也只能孤芳自赏了。
ethego
2016-01-19 14:33:31 +08:00
@xuboying 然而 javascript 越来越像 python 也是事实,看看 ecmas6 的写法就知道了
fy
2016-01-19 14:44:27 +08:00
我刚想说 nolocal

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/251731

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX