如何将func_closure条目映射到变量名称?

Thi*_*ter 7 python cpython python-2.x

我有一个在此函数中创建的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))
Run Code Online (Sandbox Code Playgroud)

使用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>)
Run Code Online (Sandbox Code Playgroud)

仔细观察(cell_contents每个cell对象的属性)向我展示:

>>> [c.cell_contents for c in func.func_closure]
['categoryDisplay',
 <function indico.web.flask.util.RHCategoryDisplay>,
 '/<categId>/',
 {}]
Run Code Online (Sandbox Code Playgroud)

lambda函数是由这个调用创建的:

add_url_rule('/<categId>/', 'categoryDisplay', rh_as_view(RHCategoryDisplay))
Run Code Online (Sandbox Code Playgroud)

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

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

Mar*_*ers 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        
Run Code Online (Sandbox Code Playgroud)

所以订单是在编译时确定的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)))
Run Code Online (Sandbox Code Playgroud)


Thi*_*ter 5

感谢Freenode上的#python中的YHg1s,我发现它是:func_code.co_freevars包含闭包中元素的变量名的元组.

>>> func.func_code.co_freevars
('endpoint', 'view_func', 'rule', 'options')
Run Code Online (Sandbox Code Playgroud)

因此,创建一个dict映射名称到闭包值很容易:

>>> 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>}
Run Code Online (Sandbox Code Playgroud)