簡體   English   中英

遞歸閉包(函數發生器)

[英]recursive closures (function generator)

我一直在學習函數式編程,我開始思考,組裝數學運算符。 counting -> addition -> multiplication -> power -> ...自然而然地出來了簡單而且最天真的代碼來表達這一點並且它有效! 問題是我真的不知道為什么它能如此好地運行並且輸出如此大的輸出。

問題是:這個功能的復雜性是什么?

代碼在python中:

def operator(d):
        if d<=1:
                return lambda x,y:x+y
        else:
                return lambda x,y:reduce(operator(d-1),(x for i in xrange(y)))


#test 
f1 = operator(1)       #f1 is adition
print("f1",f1(50,52))  #50+52

f2 = operator(2)      #f2 is multiplication
print("f2",f2(2,20))  #2*20

f3 = operator(3)      #f3 is power, just look how long output can be
print("f3",f3(4,100)) #4**100 

f4 = operator(4)      #f4 is superpower, this one does not work that well
print("f4",f4(2,6))   #((((2**2)**2)**2)**2)**2

f5 = operator(5)      #f5 do not ask about this one, 
print("f5",f5(2,4))   #

輸出(即時):

('f1', 102)
('f2', 40)
('f3', 1606938044258990275541962092341162602522202993782792835301376L)
('f4', 4294967296L)
('f5', 32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230656L)

反匯編告訴你這里沒有應用任何魔法優化,它實際上只是對genexpr的減少。 Python似乎完全可以完成這項任務,即使它讓你感到驚訝。

>>> import dis
>>> dis.dis(f3)
  5           0 LOAD_GLOBAL              0 (reduce)
              3 LOAD_GLOBAL              1 (operator)
              6 LOAD_DEREF               1 (d)
              9 LOAD_CONST               1 (1)
             12 BINARY_SUBTRACT     
             13 CALL_FUNCTION            1
             16 LOAD_CLOSURE             0 (x)
             19 BUILD_TUPLE              1
             22 LOAD_CONST               2 (<code object <genexpr> at 0x7f32d325f830, file "<stdin>", line 5>)
             25 MAKE_CLOSURE             0
             28 LOAD_GLOBAL              2 (xrange)
             31 LOAD_FAST                1 (y)
             34 CALL_FUNCTION            1
             37 GET_ITER            
             38 CALL_FUNCTION            1
             41 CALL_FUNCTION            2
             44 RETURN_VALUE

如果您專門查看f5(2,4)調用,它實際上不執行這么多操作:

>>> counter = 0
>>> def adder(x, y):
...   global counter
...   counter += 1
...   return x + y
... 
>>> def op(d):
...   if d <= 1: return adder
...   return lambda x,y:reduce(op(d-1),(x for i in xrange(y)))
...
>>> op(5)(2,4)
32317006071311007300714876688669951960444102669715484032130345427524655138867890893197201411522913463688717960921898019494119559150490921095088152386448283120630877367300996091750197750389652106796057638384067568276792218642619756161838094338476170470581645852036305042887575891541065808607552399123930385521914333389668342420684974786564569494856176035326322058077805659331026192708460314150258592864177116725943603718461857357598351152301645904403697613233287231227125684710820209725157101726931323469678542580656697935045997268352998638215525166389437335543602135433229604645318478604952148193555853611059596230656L
>>> counter
65035
>>> counter = 0
>>> op(3)(4,100)
>>> counter
297

65k的新增功能,更不用說297的取冪,甚至不值得談到搞笑優化的現代CPU,所以毫無疑問,它會在眨眼之間完成。 嘗試增加的論據之一,看看如何打快速評估的邊框十分迅速。

順便說一下, operator是一個內置模塊,你不應該像這樣命名自己的函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM