多个匿名 Python 函数的包装器

Wrapper for multiple anonymous Python functions

我一直在学习 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 函数,解释器是自动为所有内部函数分配内存,还是仅在调用后为特定的内部函数分配内存从主要代码?

这段代码到底有多有效?

据我所知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>)

但是当调用 anonwrap:

时,当适当的分支是 "hit" 时,它只会创建一个函数(MAKE_FUNCTION 操作码)
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

我个人会说代码本身不是很有效,既不利于将来的维护也不利于性能。创建代码对象只完成一次,但将它们转换(或编译 - 不确定这里的语言)到函数对象可能有点昂贵。


一个额外的评论:如果你想保持命名空间干净,你通常使用子模块(甚至 类)来 "bundle" 函数。内部函数(或如您所说的 "anonymous functions")主要用于 closures (for example decorators)。