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
ctrlaltdeletel 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
想想不能手动控制传值传引用是很蛋疼。。。
|