在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应该提供模式/搜索/替换值。
如果没有,如果所有的match_rules函数都已经被改为不同的函数,那么f2 3 4 5可能会结束生效并且消失。他们没用了。
我不知道,这就是动态语言的工作原理和构建方式。
pythontutor.com分析DIGRAM真让我感到惊讶,导师做得很好
如果你没有使它过期,请复制下面的链接并将我的代码粘贴到其中。我打赌你很开心。
答案 0 :(得分: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转换回对象。
我必须这样做,以便能够在不存储对框架的引用的情况下获取框架(Usualy weakref
执行此操作,但不执行frame
个对象。)
请注意gc.collect
后框架消失了。一旦函数完成,就不需要这些帧,但是有一些循环引用阻止了它们的立即删除。 gc.collect
足够聪明,可以检测到这些并删除不需要的帧。使用不同的代码,即使不调用gc.collect
也可能发生这种情况,我相信它也应该发生在http://pythontutor.com/中,但是它们的内部与garbace收集器存在某种冲突。