<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 403, comments - 310, trackbacks - 0, articles - 7
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    [zz]True closure in Python

    Posted on 2008-02-11 16:18 ZelluX 閱讀(813) 評論(0)  編輯  收藏 所屬分類: Scripting
    發現自己對Python的語法的興趣遠比對使用Python本身的興趣濃厚得多
    為什么水木上的帖子每行末尾都是用空格填充的,每次轉載還要先放到vim里面處理一下。。。

    by ilovecpp

    讓Python支持true closure有多難?
    只需修改11行代碼。

    如果你不知道什么是true closure,這里簡單解釋一下。Python支持lexicalscope:

    >>> def add_n(n):
    ...     def f(m):
    ...             return n+m
    ...     return f
    >>> add_2 = add_n(2)
    >>> add_2(0)
    2
    >>> add_2(2)
    4

    f引用了外層函數add_n的局部變量n。有趣的是,f引用n的時候,add_n已經結束,n似乎不存在了。f所以能正常工作,是因為創建它的時候就把n作為f的上下文(closure)保存了下來,并不隨add_n結束而消失。
    但是,Python的lexical scope和Scheme/Smalltalk/Ruby還有一點區別:不能在內層函數中rebind外層函數的局部變量。
    >>> def f():
    ...     def g():
    ...             n=1
    ...     n=0
    ...     g()
    ...     return n
    ...
    >>> f()
    0

    這是因為Python沒有變量聲明, n=1 自動使n成為g的局部變量,也就無法rebind f中的n了。可以說Python的closure是只讀的。如果你聽到有人說"Python不支持true closure",就是指這個。其實,Python VM能夠支持true closure。因為,Python支持內層函數看見外層函數的name rebinding:

    >>> def f():
    ...     def g():
    ...             yield n
    ...             yield n
    ...     x = g()
    ...     n = 0
    ...     print x.next()
    ...     n = 1
    ...     print x.next()
    ...
    >>> f()
    0
    1

    對于Python的closure實現(flat closure),"外層函數rebind name"和"內層函數rebind name"其實沒有區別。我們知道用global關鍵字可以rebind module scopename。如果增加一個類似的outer關鍵字,就可以支持rebind outer scope name。真正的限制是Guido不愿意為支持true closure增加關鍵字。

    也可以不增加關鍵字,而是把global n的語義改為"如果outer scope定義了n,rebind outer scope n;否則rebind module scope n"。簡單起見,我沒有修改Python的built-in compiler,而是修改了compiler module(用Python實現的Python compiler)。你只需把下面這個patch打到compiler/symbols.py(Python 2.5.1)就可以體驗true closure了:

    C:\Python\Lib>diff -u compiler/symbols.py.orig compiler/symbols.py
    --- compiler/symbols.py.orig    Thu Aug 17 10:28:56 2006
    +++ compiler/symbols.py Mon Feb 11 12:03:01 2008
    @@ -21,6 +21,7 @@
             self.params = {}
             self.frees = {}
             self.cells = {}
    +        self.outers = {}
             self.children = []
             # nested is true if the class could contain free variables,
             # i.e. if it is nested within another function.
    @@ -54,8 +55,10 @@
             if self.params.has_key(name):
                 raise SyntaxError, "%s in %s is global and parameter" % \
                       (name, self.name)
    -        self.globals[name] = 1
    -        self.module.add_def(name)
    +        if self.nested:
    +            self.outers[name] = 1
    +        else:
    +            self.globals[name] = 1

         def add_param(self, name):
             name = self.mangle(name)
    @@ -90,6 +93,8 @@
             """
             if self.globals.has_key(name):
                 return SC_GLOBAL
    +        if self.outers.has_key(name):
    +            return SC_FREE
             if self.cells.has_key(name):
                 return SC_CELL
             if self.defs.has_key(name):
    @@ -107,6 +112,7 @@
                 return ()
             free = {}
             free.update(self.frees)
    +        free.update(self.outers)
             for name in self.uses.keys():
                 if not (self.defs.has_key(name) or
                         self.globals.has_key(name)):
    @@ -134,6 +140,9 @@
             free.
             """
             self.globals[name] = 1
    +        if self.outers.has_key(name):
    +            self.module.add_def(name)
    +            del self.outers[name]
             if self.frees.has_key(name):
                 del self.frees[name]
             for child in self.children:

    因為我們沒有修改built-in compiler,所以程序要寫在字符串里,用compiler.compile編譯,用exec執行:
    >>> from compiler import compile
    >>> s = '''
    ... def counter():
    ...     n = 0
    ...     def inc():
    ...             global n
    ...             n += 1
    ...     def dec():
    ...             global n
    ...             n -= 1
    ...     def get():
    ...             return n
    ...     return inc, dec, get
    ... '''
    >>> exec compile(s, '', 'exec')
    >>> inc, dec, get = counter()
    >>> get()
    0
    >>> inc()
    >>> get()
    1
    >>> dec()
    >>> get()
    0

    后記

    1 搞這個東西的緣起是Selfless Python(http://www.voidspace.org.uk/python/weblog/arch_d7_2006_12_16.shtml#e583)。很有趣的bytecode hack,給一個類中的所有函數補上self參數。既然PythonVM支持true closure,能不能用類似的手法讓Python支持true closure呢?不過很快就明白這個在bytecode層面不好弄,還是得修改編譯器。不過改起來還真是出乎意料地簡單。

    2 Guido早已明確表示不能改變global的語義(因為會影響現有代碼),所以這個只是玩玩而已,不用指望成為現實。當然你可以只發布bytecode,大概還能把反編譯器搞掛掉。:-)
    3 我可以理解Guido的決定。除非你之前一直在用Scheme,否則我覺得像上面counter例子那種一組共享狀態的函數還是寫成class為好,至少共享狀態是什么一目了然。Lexical scope太implicit,用在開頭add_n那種地方挺方便,再復雜就不好了。

    又:很抱歉"幕后的故事"拖了這么久。寫起來才發現自己還是不懂descriptor。
    不過我肯定不會讓它爛尾的。

     

    主站蜘蛛池模板: 亚洲人成色7777在线观看| 亚洲А∨精品天堂在线| 国产亚洲精AA在线观看SEE| 日本一区二区在线免费观看 | 亚洲 无码 在线 专区| 亚洲欧美第一成人网站7777| 在线观看AV片永久免费| 亚洲乱码在线观看| 免费黄色app网站| 国产亚洲日韩在线a不卡| 国产在线不卡免费播放| 曰批免费视频播放在线看片二| 国产jizzjizz免费视频| 日本一区二区在线免费观看| 久久亚洲精品无码观看不卡| 成全视频在线观看免费| 久久久久久亚洲精品成人| 3344免费播放观看视频| 亚洲日韩乱码中文字幕| 免费a级毛片永久免费| 9久热精品免费观看视频| 精品久久久久久亚洲| 最近免费中文字幕大全高清大全1 最近免费中文字幕mv在线电影 | 国产偷国产偷亚洲高清日韩| 中国一级特黄的片子免费 | 亚洲国产精品无码中文字| 无人在线观看免费高清| 77777亚洲午夜久久多喷| 国产免费直播在线观看视频| 99re6在线视频精品免费| 亚洲专区在线视频| 浮力影院第一页小视频国产在线观看免费 | 亚洲精品少妇30p| 全免费毛片在线播放| 亚洲av午夜电影在线观看| 亚洲精品无码99在线观看| 99久久人妻精品免费二区| 亚洲精品第一国产综合亚AV| 亚洲色婷婷综合开心网| 99re6免费视频| 精品在线免费视频|