2017-08-08 65 views
2

我一直在学习关于Python函数和函数的一般情况,并且我遇到了匿名函数的这种想法,其优点显然是保持名称空间清洁以及不分配额外的内存,因为一个函数只被分配给一个变量才会被执行。多个匿名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功能在代码中被定义,解释器是否为所有内部函数自动分配内存,或者只是在从主代码调用特定内部函数时才分配内存?

这段代码有多有效?

+2

我相信当你说'匿名'函数将会是'lambda'时[这里](http://www.diveintopython.net/power_of_introspection/lambda_functions.html) –

+1

谢谢你的回复。我知道lambda。不幸的是,Python中的lambda表达式仅限于单个表达式,并且他们不接受使用语句或将其他函数包含在其身体中。 – Regardless

+0

也只是出于好奇,为什么第三个'anon'函数'print'而不是'return'''不知道'' –

回答

2

至于我可以看到它的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)。

+0

我想要使用内部函数的想法是尽可能接近在JS或Go等其他语言中使用真正的匿名函数: 'myvar = function(args){statement1;语句2;返回值}' 因此我称他们为匿名,他们是。 看起来Python在这方面的能力有些不足。 你的回答是绝对彻底的。非常感激。 – Regardless

+1

@Regardless基于内省优化代码的语言在这里有着明显的优势,因为他们可能意识到可以提前编译函数,因为没有关闭。不过,我可能夸大了一点:编译代码对象中的函数对象并不慢,只是速度不快。但在Python中有这些内部函数的用例 - 但我不会在你的情况下使用它们。你可以在这里用更简单的方法达到同样的效果。 – MSeifert

+0

@Regardless如果它解决了您的问题,请不要忘记[接受](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work)答案。如果它不能解决你的问题(或者你想等待更多的答案),请随时留下它的答案。 – MSeifert