
1 bcxx 2014-03-30 22:15:23 +08:00 是的,你说的对 |
2 casparchen 2014-03-30 22:16:42 +08:00 对的 |
3 tioover OP 嗯,刚刚写了一大堆,提交编辑却说没办法,我重新写。 |
4 tioover OP 是这样的,我在写一个 Lisp 解释器,里面要实现闭包,可是 Python 里面没有指针 |
5 tioover OP 比如说 def foobar(): ....foo = 1 ....def bar(): ........return foo 在这种情况下,foobar() 的环境是 {"foo": 1} 按照一般思路,bar() 里面找不到 foo,就往上层作用域找 |
6 bcxx 2014-03-30 22:24:28 +08:00 你设计一个 context 将函数运行的状态(就是运行环境)注入进去就行(解释器解释的时候根据这个 context 来解释) |
7 tioover OP 问题是 bar 如果作为一个返回值返回,foo 的环境应该删除 |
8 bcxx 2014-03-30 22:26:51 +08:00 @tioover 应该是将 bar 的运行环境和 bar 绑定了一起返回(就是不返回 function,而是返回 function + context,也就是整个闭包。) |
9 tioover OP 所以应该 bar 的环境里包括 bar 里面的自由变量 {"foo": parent_env["foo"]} 但是这样的话上层的变量变更了以后bar里面的foo还是1 def foobar(): ....foo = 1 ....def bar(): ........return foo ....foo = 2 |
10 tioover OP 所以应该传递指向数据的指针,Python 里面没有指针,但是被容器(class)容纳的数据是必然传递指针的,比如说 [] 所以我想可以用 class Ptr 来模拟指针 env["foo"] = Ptr(data) 这样就可以了,但是感觉不美好 |
12 tioover OP 接 #10 在 bar 的闭包中,只需要 env["foo"] = parent["foo"] 就行 复制就是 parent["foo"].ptr = data 这样就行了。 但是用指针模拟总感觉很糟 |
17 tioover OP 忘了还有附言了,把内容放在附言里面…… |
19 cadl 2014-03-31 01:01:35 +08:00 via Android 额 没太清楚为什么foo的值会被修改,以及被修改了为什么要影响bar环境中foo的值 |
20 tioover OP @ctrlaltdeletel 在 Python 里面你改一样东西的值,其实是新创建一个对象然后修改指针,不能直接修改指针的内容。 后者是闭包的特性… |
21 rannnn 2014-03-31 07:31:54 +08:00 PO主是在写解释器还是写lisp->py的编译器? |
22 aristotle9 2014-03-31 11:11:33 +08:00 "但是 bar() 这个闭包函数是一个独立的,不应该依赖于 foobar() 的环境,不然只要 bar 存在,foobar 就不能被回收。" 这个说法不太对. 函数bar()依赖定义他的环境(词法作用域), 包括foobar的环境. foobar()可以回收, 但是他的环境还是会被引用到(如果bar()或者其他定义在其中的函数没有回收的话), 函数对环境的引用是单向的. 当所有引用某个环境的函数都被回收后, 该环境才会回收. 所以在设计上, 环境与函数是独立的, 可以把任意一个函数拿到任意一个环境中去求值. 环境的结构是一个map: ENV = {parent: ENV(上一层), data: {foo: 1,...}} PO主可以去看看 ECMA-262或者http://www.eopl3.com/ |
23 exch4nge 2014-03-31 13:20:42 +08:00 额,回不回收的我不大懂。 def foobar(): ....foo = 1 ....def bar(): ........return foo ....foo = 2 (话说如果bar被调用的话正确返回应该是2对吧……) 这时候foobar的context里是有变量foo的。 getContext(foobar) --> { foo: ?? } 建立bar的context的时候,bar的context只知道自己的context的parent是foobar的context。 getContext(bar).parent === getContext(foobar) 不管怎样,bar被调用的时候,肯定是在foobar函数里面所被调用的,调用的时候,foobar的context中的foo的变量是带着某个值的。然后bar里面出现foo,先从自己的context找foo变量,没有就继续递归往上找,直到找到一个,如果没找到就报错。 额,可能重点是lz的 “但是 bar() 这个闭包函数是一个独立的,不应该依赖于 foobar() 的环境”。这句话应该是不正确的吧…… |
24 exch4nge 2014-03-31 13:26:43 +08:00 补充一下。另外一个重点是遇到bar的定义的时候,不应该把foo的值传进去当作bar的context的。foo一直是foobar的context里面的变量 |
25 exch4nge 2014-03-31 13:44:16 +08:00 ……没法删评论,好吧,我上面的理解是错的,大家请无视…… 闭包是包含foo这样的东西的…… |
26 tioover OP @exch4nge def foobar(): ....foo = 1 ....def bar(): ........return foo ....foo = 2 ....return bar() 可以这样搞…… |
27 tioover OP |
28 gladuo 2018-10-27 14:59:39 +08:00 想想不能手动控制传值传引用是很蛋疼。。。 |