代码之家  ›  专栏  ›  技术社区  ›  Regardless

多个匿名Python函数的包装器

  •  2
  • Regardless  · 技术社区  · 7 年前

    我一直在学习Python函数和一般函数,我偶然发现了匿名函数的概念,其优点之一显然是能够保持名称空间干净,并且不分配额外内存,因为函数只在分配给变量后执行。

    在Python中,据我所知,创建匿名函数的唯一方法是将它们封装在另一个函数中。因此,我想到了为代码中的多个匿名函数创建一个容器,并通过选择器对其进行寻址,选择器本质上是使用参数调用包装器:

    def anonwrap(selector):
        if selector == "addition":
            def anon(param1, param2):
                return param1 + param2
            return anon
        elif selector == "the meaning of life":
            def anon(param1):
                return param1 + " 42"
            return anon
        else:
            def anon(*args, **kwargs):
                print("no idea")
            return anon
    select = anonwrap("addition")
    print(select(10, 20))
    select = anonwrap("the meaning of life")
    print(select("the meaning of life is"))
    select = anonwrap("hello")
    print(select("blah", 9001))
    

    anonwrap 函数在代码中定义,解释器是自动为所有内部函数分配内存,还是仅在从主代码调用特定内部函数时为其分配内存?

    这个代码到底有多有效?

    1 回复  |  直到 7 年前
        1
  •  2
  •   MSeifert    7 年前

    据我所知,Python会自动为所有内部函数创建代码对象,并将其保存为常量:

    >>> anonwrap.__code__.co_consts
    (None,
     'addition',
     <code object anon at 0x0000022BB354DD20, file "<ipython-input-78-ab41b0534822>", line 3>,
     'anonwrap.<locals>.anon',
     'the meaning of life',
     <code object anon at 0x0000022BB354D780, file "<ipython-input-78-ab41b0534822>", line 7>,
     <code object anon at 0x0000022BB354DE40, file "<ipython-input-78-ab41b0534822>", line 11>)
    

    MAKE_FUNCTION 操作码),当调用时相应的分支被“命中” anonwrap :

    import dis
    
    dis.dis(anonwrap)
    
      2           0 LOAD_FAST                0 (selector)
                  2 LOAD_CONST               1 ('addition')
                  4 COMPARE_OP               2 (==)
                  6 POP_JUMP_IF_FALSE       20
    
      3           8 LOAD_CONST               2 (<code object anon at 0x0000022BB3434A50, file "<ipython-input-74-bb454d2da558>", line 3>)
                 10 LOAD_CONST               3 ('anonwrap.<locals>.anon')
                 12 MAKE_FUNCTION            0
                 14 STORE_FAST               1 (anon)
    
      5          16 LOAD_FAST                1 (anon)
                 18 RETURN_VALUE
    
      6     >>   20 LOAD_FAST                0 (selector)
                 22 LOAD_CONST               4 ('the meaning of life')
                 24 COMPARE_OP               2 (==)
                 26 POP_JUMP_IF_FALSE       40
    
      7          28 LOAD_CONST               5 (<code object anon at 0x0000022BB354DC00, file "<ipython-input-74-bb454d2da558>", line 7>)
                 30 LOAD_CONST               3 ('anonwrap.<locals>.anon')
                 32 MAKE_FUNCTION            0
                 34 STORE_FAST               1 (anon)
    
      9          36 LOAD_FAST                1 (anon)
                 38 RETURN_VALUE
    
     11     >>   40 LOAD_CONST               6 (<code object anon at 0x0000022BB354DC90, file "<ipython-input-74-bb454d2da558>", line 11>)
                 42 LOAD_CONST               3 ('anonwrap.<locals>.anon')
                 44 MAKE_FUNCTION            0
                 46 STORE_FAST               1 (anon)
    
     13          48 LOAD_FAST                1 (anon)
                 50 RETURN_VALUE
                 52 LOAD_CONST               0 (None)
                 54 RETURN_VALUE
    

    就个人而言,我想说的是,代码本身不是很有效,无论是对未来的维护还是对性能。创建代码对象只需执行一次,但将这些对象转换(或编译-此处不确定使用何种语言)为函数对象可能有点昂贵。


    closures (例如 decorators ).