2017-08-08 97 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