【问题标题】:Python dynamic function building and closure rulePython动态函数构建和闭包规则
【发布时间】:2017-02-24 17:02:10
【问题描述】:

http://pythontutor.com/visualize.html 中以交互方式执行以下代码时,每次调用build_match_and_apply_functions 的框架在图形视图中显示为灰色:

这个程序用于获取单词的复数,引用自Python 3中的DIVE章节

代码:

import re

def build_match_and_apply_functions(pattern, search, replace):
    def matches_rule(word):                                   
        return re.search(pattern, word)
    def apply_rule(word):                                     
        return re.sub(search, replace, word)
    return (matches_rule, apply_rule)        

patterns =  \
    (
    ('[sxz]$',           '$',  'es'),
    ('[^aeioudgkprt]h$', '$',  'es'),
    ('(qu|[^aeiou])y$',  'y$', 'ies'),
    ('$',                '$',  's')
  )
rules = [build_match_and_apply_functions(pattern, search, replace)  
         for (pattern, search, replace) in patterns]


def plural(noun):
    for matches_rule, apply_rule in rules: 
        if matches_rule(noun):
            return apply_rule(noun)


plural('vacancy')

问题:

1) 灰框是什么意思?它是一个仍然占用内存的闭包?

2) 我可以进入内存块吗?所以我可以在对象区域中弄清楚,所有matches_rule函数是否相同?如果它们相同,f2/f3/f4/f5 应该在那里提供模式/搜索/替换值。

如果不是,如果所有matches_rules 函数都已更改为不同的函数,则f2 3 4 5 可能会结束并消失。它们没用。

我不知道,这就是动态语言的工作原理和构建方式。


pythontutor.com ANALYZE DIGRAM 真的让我很惊讶,导师做得很好

如果你没有过期,请复制下面的链接并粘贴我的代码。我打赌你玩得很开心。

http://pythontutor.com/visualize.html

【问题讨论】:

    标签: python functional-programming closures


    【解决方案1】:

    灰色框架是执行框架,其中包含闭包。它们理论上可以从内存中读取。

    例如,我设法使用以下代码(CPython v3.5)从帧中读取数据:

    首先是一些实用程序:

    import gc, inspect, ctypes, random
    
    def all_live_ids():
        """Get all valid object IDs"""
        for obj in gc.get_objects():
            yield id(obj)
    
    def getobj(obj_id):
        """Get the object from object ID"""
        if obj_id in all_live_ids():
            return ctypes.cast(obj_id, ctypes.py_object).value
        else:
            return None
    
    frame_ids = []
    
    def print_frames():
        for fid in frame_ids:
            frame = getobj(fid)
            if frame:
                print('frame', hex(fid), 'is alive and has pattern:',
                       frame.f_locals['pattern'])
            else:
                print('frame', hex(fid), 'is dead')
    

    然后是问题中代码的简化版本:

    def build_match_and_apply_functions(pattern, search, replace):
        frame = inspect.currentframe()
        frame_ids.append(id(frame))
        print('executing frame', frame, 'pattern:', pattern)
        def matches_rule(word):                                   
            return re.search(pattern, word)
        return matches_rule
    
    rule1 = build_match_and_apply_functions('[sxz]$', '$', 'es')
    rule2 = build_match_and_apply_functions('[^aeioudgkprt]h$', '$', 'es')
    
    print('\nbefore gc.collect():')
    print_frames()
    
    gc.collect()
    
    print('\nafter gc.collect():')
    print_frames()
    

    在我的例子中,它打印:

    executing frame <frame object at 0x0071EDB0> pattern: [sxz]$
    executing frame <frame object at 0x00C0E4B0> pattern: [^aeioudgkprt]h$
    
    before gc.collect():
    frame 0x71edb0 is alive and has pattern: [sxz]$
    frame 0xc0e4b0 is alive and has pattern: [^aeioudgkprt]h$
    
    after gc.collect():
    frame 0x71edb0 is dead
    frame 0xc0e4b0 is dead
    

    我做了什么?

    我记得frame_ids 中所有帧的 ID。在 CPython 中,id 返回对象的内存地址。

    然后我使用this solution 将 ID 转换回对象。

    我必须这样做才能在不存储对框架的引用的情况下获取框架(通常 weakref 会这样做,但不会使用 frame 对象`)

    有一个问题

    请注意,在gc.collect 之后框架消失了。一旦函数完成就不需要这些帧,但是有一些循环引用阻止了它们的立即删除。 gc.collect 足够聪明,可以检测到这些并删除不需要的帧。使用不同的代码,即使不调用 gc.collect 也可能发生这种情况,我相信它也应该发生在 http://pythontutor.com/ 中,但它们的内部与垃圾收集器存在某种冲突。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-21
      • 2019-12-07
      • 2010-11-22
      • 1970-01-01
      • 2011-12-24
      • 1970-01-01
      • 2021-12-17
      • 1970-01-01
      相关资源
      最近更新 更多