7

この関数で作成されたラムダ オブジェクトがあります。

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_closureラムダ関数オブジェクトを使用すると、ラムダ関数のクロージャ スコープにアクセスできます。

(<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>/',
 {}]

そのラムダ関数は、次の呼び出しによって作成されました。

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

ご覧のとおり、順序は関数の引数の順序やラムダ内で引数が使用される順序と一致しません。タイプ/コンテンツに基づいて、どの要素が何であるかを簡単に見つけることができましたが、よりクリーンな方法で行いたいと思います。

だから私の質問は、元の変数名(または関数引数の場合は少なくとも位置)にどのように関連付けることができますか?

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()を使用して、それ自体が python 辞書になっています。dictbytype()

したがって、クロージャーの順序は実際には任意 (ハッシュ テーブルの順序) であり、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 を作成するのは簡単です。

>>> 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 に答える