<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 閱讀(819) 評論(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。
    不過我肯定不會讓它爛尾的。

     

    主站蜘蛛池模板: 精品乱子伦一区二区三区高清免费播放 | 婷婷亚洲综合一区二区| 亚洲视频在线免费观看| 久久精品九九亚洲精品天堂| 国产99精品一区二区三区免费 | 亚洲精品国产av成拍色拍| 在线看片无码永久免费视频| 亚洲成a人片7777| 丁香花免费高清视频完整版| 亚洲特级aaaaaa毛片| 亚洲精品国产免费| 亚洲人成在线精品| 成年人免费观看视频网站| 亚洲欧美不卡高清在线| 无码国模国产在线观看免费| 国产在亚洲线视频观看| 国产啪亚洲国产精品无码| a级毛片毛片免费观看久潮| 亚洲AV无码久久精品蜜桃| 四虎成年永久免费网站| 亚洲熟女乱色一区二区三区| 国产成人免费ā片在线观看| jizz中国免费| 亚洲精品网站在线观看你懂的| 拍拍拍又黄又爽无挡视频免费| 亚洲heyzo专区无码综合| 久久久久亚洲精品无码网址| 日本免费在线中文字幕| 一本色道久久88亚洲精品综合 | 色九月亚洲综合网| 亚洲熟妇丰满多毛XXXX| 免费看又黄又无码的网站| 伊人久久亚洲综合影院首页| 国产亚洲人成网站在线观看| 四虎在线最新永久免费| 黄色a三级免费看| 亚洲福利视频网址| 亚洲成aⅴ人片久青草影院| 日韩人妻无码精品久久免费一| 亚洲日韩中文字幕一区| 亚洲精品少妇30p|