这种时候怎么实现?我只能觉得用类模拟指针了…… - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
tioover
V2EX    Python

这种时候怎么实现?我只能觉得用类模拟指针了……

  •  
  •   tioover
    tioover 2014-03-30 22:09:30 +08:00 4895 次点击
    这是一个创建于 4291 天前的主题,其中的信息可能已经有所发展或是发生改变。
    不小心发出来了,我在回复里面说
    第 1 条附言    2014-03-30 22:44:49 +08:00
    比如说

    def foobar():
    ....foo = 1
    ....def bar():
    ........return foo

    在这种情况下,foobar() 的环境是 {"foo": 1}
    按照一般思路,bar() 里面找不到 foo,就往上层作用域找。

    但是 bar() 这个闭包函数是一个独立的,不应该依赖于 foobar() 的环境,不然只要 bar 存在,foobar 就不能被回收。
    所以应该 bar 的环境里包括 bar 里面的自由变量 {"foo": parent_env["foo"]}。

    但是这样的话上层的变量变更了以后bar里面的foo还是1


    def foobar():
    ....foo = 1
    ....def bar():
    ........return foo
    ....foo = 2

    所以应该传递指向数据的指针,Python 里面没有指针,但是被容器(class)容纳的数据是必然传递指针的,比如说 []

    所以我想可以用 class Ptr:ptr=None 来模拟指针

    env["foo"] = Ptr(data)


    在 bar 的闭包中,只需要

    env["foo"] = parent["foo"] 就行

    复制就是 parent["foo"].ptr = data 这样就行了。

    但是用类模拟指针总感觉很糟。
    28 条回复    2018-10-27 14:59:39 +08:00
    bcxx
        1
    bcxx  
       2014-03-30 22:15:23 +08:00
    是的,你说的对
    casparchen
        2
    casparchen  
       2014-03-30 22:16:42 +08:00
    对的
    tioover
        3
    tioover  
    OP
       2014-03-30 22:18:09 +08:00
    嗯,刚刚写了一大堆,提交编辑却说没办法,我重新写。
    tioover
        4
    tioover  
    OP
       2014-03-30 22:18:49 +08:00
    是这样的,我在写一个 Lisp 解释器,里面要实现闭包,可是 Python 里面没有指针
    tioover
        5
    tioover  
    OP
       2014-03-30 22:21:17 +08:00
    比如说

    def foobar():
    ....foo = 1
    ....def bar():
    ........return foo

    在这种情况下,foobar() 的环境是 {"foo": 1}
    按照一般思路,bar() 里面找不到 foo,就往上层作用域找
    bcxx
        6
    bcxx  
       2014-03-30 22:24:28 +08:00
    你设计一个 context 将函数运行的状态(就是运行环境)注入进去就行(解释器解释的时候根据这个 context 来解释)
    tioover
        7
    tioover  
    OP
       2014-03-30 22:24:51 +08:00
    问题是 bar 如果作为一个返回值返回,foo 的环境应该删除
    bcxx
        8
    bcxx  
       2014-03-30 22:26:51 +08:00
    @tioover 应该是将 bar 的运行环境和 bar 绑定了一起返回(就是不返回 function,而是返回 function + context,也就是整个闭包。)
    tioover
        9
    tioover  
    OP
       2014-03-30 22:27:15 +08:00
    所以应该 bar 的环境里包括 bar 里面的自由变量 {"foo": parent_env["foo"]}
    但是这样的话上层的变量变更了以后bar里面的foo还是1


    def foobar():
    ....foo = 1
    ....def bar():
    ........return foo
    ....foo = 2
    tioover
        10
    tioover  
    OP
       2014-03-30 22:28:56 +08:00
    所以应该传递指向数据的指针,Python 里面没有指针,但是被容器(class)容纳的数据是必然传递指针的,比如说 []

    所以我想可以用 class Ptr 来模拟指针

    env["foo"] = Ptr(data)

    这样就可以了,但是感觉不美好
    tioover
        11
    tioover  
    OP
       2014-03-30 22:29:37 +08:00
    @bcxx 我就是这个意思……刚刚想说完再回复
    tioover
        12
    tioover  
    OP
       2014-03-30 22:32:01 +08:00
    接 #10
    在 bar 的闭包中,只需要

    env["foo"] = parent["foo"] 就行

    复制就是 parent["foo"].ptr = data 这样就行了。

    但是用指针模拟总感觉很糟
    bcxx
        13
    bcxx  
       2014-03-30 22:33:41 +08:00
    @tioover 你可以看看 lisp / racket 之类是怎样做的……
    tioover
        14
    tioover  
    OP
       2014-03-30 22:34:39 +08:00
    @bcxx 人家背后直接能用指针吧 = = 用 Python 只能用这种曲线的方法实现
    bcxx
        15
    bcxx  
       2014-03-30 22:39:57 +08:00
    @tioover 额,你太执着名字上的东西了= = 那时语义上的实现啊,你底层具体怎么实现是另外一回事啊
    tioover
        16
    tioover  
    OP
       2014-03-30 22:41:31 +08:00
    @bcxx 我是觉得用一个 class 去模拟指针不美……
    tioover
        17
    tioover  
    OP
       2014-03-30 22:45:07 +08:00
    忘了还有附言了,把内容放在附言里面……
    bcxx
        18
    bcxx  
       2014-03-30 22:56:04 +08:00
    @tioover = = 不能理解
    cadl
        19
    cadl  
       2014-03-31 01:01:35 +08:00 via Android
    额 没太清楚为什么foo的值会被修改,以及被修改了为什么要影响bar环境中foo的值
    tioover
        20
    tioover  
    OP
       2014-03-31 01:52:23 +08:00 via Android
    @ctrlaltdeletel 在 Python 里面你改一样东西的值,其实是新创建一个对象然后修改指针,不能直接修改指针的内容。
    后者是闭包的特性…
    rannnn
        21
    rannnn  
       2014-03-31 07:31:54 +08:00
    PO主是在写解释器还是写lisp->py的编译器?
    aristotle9
        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/
    exch4nge
        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() 的环境”。这句话应该是不正确的吧……
    exch4nge
        24
    exch4nge  
       2014-03-31 13:26:43 +08:00
    补充一下。另外一个重点是遇到bar的定义的时候,不应该把foo的值传进去当作bar的context的。foo一直是foobar的context里面的变量
    exch4nge
        25
    exch4nge  
       2014-03-31 13:44:16 +08:00
    ……没法删评论,好吧,我上面的理解是错的,大家请无视……

    闭包是包含foo这样的东西的……
    tioover
        26
    tioover  
    OP
       2014-03-31 14:36:52 +08:00
    @exch4nge

    def foobar():
    ....foo = 1
    ....def bar():
    ........return foo
    ....foo = 2
    ....return bar()
    可以这样搞……
    tioover
        27
    tioover  
    OP
       2014-03-31 14:37:15 +08:00
    @exch4nge

    def foobar():
    ....foo = 1
    ....def bar():
    ........return foo
    ....foo = 2
    ....return bar
    上面的说错了……
    gladuo
        28
    gladuo  
       2018-10-27 14:59:39 +08:00
    想想不能手动控制传值传引用是很蛋疼。。。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3421 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 04:32 PVG 12:32 LAX 20:32 JFK 23:32
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86