7

我有一个在此函数中创建的 lambda 对象:

def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
    self.record(lambda s:
        s.add_url_rule(rule, endpoint, view_func, **options))

使用func_closurelambda 函数对象,我可以访问 lambda 函数的闭包范围:

(<cell at 0x3eb89f0: str object at 0x2fb4378>,
 <cell at 0x3eb8a28: function object at 0x3cb3a28>,
 <cell at 0x3eb8a60: str object at 0x3ebd090>,
 <cell at 0x3eb8b08: dict object at 0x3016ec0>)

仔细观察(cell_contents每个cell对象的属性)告诉我:

>>> [c.cell_contents for c in func.func_closure]
['categoryDisplay',
 <function indico.web.flask.util.RHCategoryDisplay>,
 '/<categId>/',
 {}]

该 lambda 函数是由该调用创建的:

add_url_rule('/<categId>/', 'categoryDisplay', rh_as_view(RHCategoryDisplay))

如您所见,顺序与函数的参数顺序或在 lambda 中使用参数的顺序不匹配。虽然我可以根据其类型/内容轻松找出哪个元素是什么,但我想以更简洁的方式进行。

所以我的问题是:如何将它与它们的原始变量名(或至少在函数参数的情况下的位置)相关联?

4

2 回答 2

13

闭包由LOAD_CLOSURE字节码创建,其顺序与它们的字节码排序相同:

>>> dis.dis(add_url_rule)
  2           0 LOAD_FAST                0 (self)
              3 LOAD_ATTR                0 (record)
              6 LOAD_CLOSURE             0 (endpoint)
              9 LOAD_CLOSURE             1 (options)
             12 LOAD_CLOSURE             2 (rule)
             15 LOAD_CLOSURE             3 (view_func)
             18 BUILD_TUPLE              4
             21 LOAD_CONST               1 (<code object <lambda> at 0x10faec530, file "<stdin>", line 2>)
             24 MAKE_CLOSURE             0
             27 CALL_FUNCTION            1
             30 POP_TOP             
             31 LOAD_CONST               0 (None)
             34 RETURN_VALUE        

所以顺序是在编译时确定的,由compiler_make_closure(); 这个函数使用func.func_code.co_freevars元组作为指导,它以相同的顺序列出闭包。

func.func_code.co_freevars在 中创建代码对象时设置makecode,并且元组是从 python 字典的键生成的,因此顺序是任意的,就像字典一样。如果你好奇,dict 是内置的compiler_enter_scope(),使用编译器符号表中命名的所有自由变量的dictbytype()实用函数,它本身就是一个 python 字典。

因此,闭包的顺序确实是任意的(哈希表排序),并且您可以使用func.func_code.co_freevars元组(可以看作是编译器处理字典键的顺序的记录)将名称附加到闭包:

dict(zip(func.func_code.co_freevars, (c.cell_contents for c in func.func_closure)))
于 2013-06-17T10:35:15.450 回答
5

感谢 Freenode 上#python 中的 YHg1s,我弄清楚了:func_code.co_freevars是一个包含闭包中元素的变量名称的元组。

>>> func.func_code.co_freevars
('endpoint', 'view_func', 'rule', 'options')

因此,创建一个将名称映射到闭包值的字典很容易:

>>> dict(zip(func.func_code.co_freevars,
             (c.cell_contents for c in func.func_closure)))
{'endpoint': 'categoryDisplay',
 'options': {},
 'rule': '/<categId>/',
 'view_func': <function indico.web.flask.util.RHCategoryDisplay>}
于 2013-06-17T10:31:02.617 回答