回答
你的問題讓我很好奇,所以我看了一些現實世界中的代碼:Python標準庫。我發現了67個嵌套函數的例子。這裏有一些解釋。
一個很簡單的理由來使用嵌套功能很簡單,就是你定義的功能並不需要是全球性的,因爲只有封閉函數使用它。從Python的quopri.py標準庫模塊一個典型的例子:
def encode(input, output, quotetabs, header = 0):
...
def write(s, output=output, lineEnd='\n'):
# RFC 1521 requires that the line ending in a space or tab must have
# that trailing character encoded.
if s and s[-1:] in ' \t':
output.write(s[:-1] + quote(s[-1]) + lineEnd)
elif s == '.':
output.write(quote(s) + lineEnd)
else:
output.write(s + lineEnd)
... # 35 more lines of code that call write in several places
在這裏有是encode
函數中一些常見的代碼,所以筆者簡單地分解出來進入write
功能。
另一個常見用途爲嵌套函數是re.sub
。下面是來自json/encode.py標準庫模塊的一些代碼:
def encode_basestring(s):
"""Return a JSON representation of a Python string
"""
def replace(match):
return ESCAPE_DCT[match.group(0)]
return '"' + ESCAPE.sub(replace, s) + '"'
這裏ESCAPE
是一個正則表達式,ESCAPE.sub(replace, s)
發現的ESCAPE
所有比賽中s
和替換每一個與replace(match)
。
事實上,任何API,像re.sub
,它接受一個函數作爲參數可能會導致出現嵌套函數是便利的情況。例如,在turtle.py有一些愚蠢的演示代碼,這是否:
def baba(xdummy, ydummy):
clearscreen()
bye()
...
tri.write(" Click me!", font = ("Courier", 12, "bold"))
tri.onclick(baba, 1)
onclick
希望你傳遞一個事件處理函數,所以我們定義一個,並通過它在
這些都是很好的例子,但它們都可以寫成全局函數而不會丟失任何功能。嵌套函數不僅僅是語法糖!你應該在需要的地方給出一些例子 – Claudiu 2010-06-05 13:57:14
也值得注意的是,嵌套函數會增加開銷。每次調用外部函數時,Python都會創建一個全新的內部函數實例。在很多情況下,這並不重要,但有時候確實如此。 – 2016-05-13 14:59:02
Decorators是嵌套函數非常流行的應用。這是一個裝飾器的例子,它在對裝飾函數進行任何調用之前和之後都會打印語句。
def entry_exit(f):
def new_f(*args, **kwargs):
print "Entering", f.__name__
f(*args, **kwargs)
print "Exited", f.__name__
return new_f
@entry_exit
def func1():
print "inside func1()"
@entry_exit
def func2():
print "inside func2()"
func1()
func2()
print func1.__name__
該死的!你擊敗了我:P – Skilldrick 2010-01-06 23:29:46
其實,這是另外一個話題去學習,但如果你看的東西上「使用功能的裝飾」,你會看到的嵌套函數的一些例子。
嵌套函數避免混亂與其他函數和變量只能使局部意義上的程序的其他部分。
返回斐波那契數的函數可以被定義如下:
>>> def fib(n):
def rec():
return fib(n-1) + fib(n-2)
if n == 0:
return 0
elif n == 1:
return 1
else:
return rec()
>>> map(fib, range(10))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
編輯:在實踐中,發電機將是這一個更好的解決方案,但該示例展示瞭如何利用嵌套函數的優勢。
可能值得注意的是,每次調用fib時,都會創建一個新的rec函數對象。在代碼清理的情況下,這通常是不可取的。對於裝飾者來說,這基本上是必要的。 – 2010-01-06 23:49:28
我只有創建裝飾時使用嵌套函數。嵌套函數基本上是向函數中添加某些行爲的一種方式,而無需知道要添加行爲的函數。
from functools import wraps
from types import InstanceType
def printCall(func):
def getArgKwargStrings(*args, **kwargs):
argsString = "".join(["%s, " % (arg) for arg in args])
kwargsString = "".join(["%s=%s, " % (key, value) for key, value in kwargs.items()])
if not len(kwargs):
if len(argsString):
argsString = argsString[:-2]
else:
kwargsString = kwargsString[:-2]
return argsString, kwargsString
@wraps(func)
def wrapper(*args, **kwargs):
ret = None
if args and isinstance(args[0], InstanceType) and getattr(args[0], func.__name__, None):
instance, args = args[0], args[1:]
argsString, kwargsString = getArgKwargStrings(*args, **kwargs)
ret = func(instance, *args, **kwargs)
print "Called %s.%s(%s%s)" % (instance.__class__.__name__, func.__name__, argsString, kwargsString)
print "Returned %s" % str(ret)
else:
argsString, kwargsString = getArgKwargStrings(*args, **kwargs)
ret = func(*args, **kwargs)
print "Called %s(%s%s)" % (func.__name__, argsString, kwargsString)
print "Returned %s" % str(ret)
return ret
return wrapper
def sayHello(name):
print "Hello, my name is %s" % (name)
if __name__ == "__main__":
sayHelloAndPrintDebug = printCall(sayHello)
name = "Nimbuz"
sayHelloAndPrintDebug(name)
忽略了「printCall」功能的所有魔神的現在和重點只有「sayHello的」功能及以下。我們在這裏做的是我們想要打印出每次調用「sayHello」函數時如何調用,而不知道或改變「sayHello」函數的作用。因此,我們通過將「sayHello」函數傳遞給「printCall」來重新定義「sayHello」函數,該函數返回一個NEW函數,該函數執行「sayHello」函數的功能並打印「sayHello」函數的調用方式。這是裝飾者的概念。
把「@printCall」的定義的sayHello上面完成同樣的事情:
@printCall
def sayHello(name):
print "Hello, my name is %s" % (name)
if __name__ == "__main__":
name = "Nimbuz"
sayHello(name)
他們使用的時候非常有用。將其他功能作爲輸入的功能。說你是在一個函數,並且要排序的字典基礎上,項目的價值的項目清單:
def f(items):
vals = {}
for i in items: vals[i] = random.randint(0,100)
def key(i): return vals[i]
items.sort(key=key)
你可以只定義關鍵在那裏,並用它瓦爾斯,一個局部變量。
另一個用例是回調函數。
好的,除了裝飾者:假設你有一個應用程序,你需要根據不斷變化的子串排序一個字符串列表。現在,sorted
函數採用key=
參數,該參數是一個參數的函數:要排序的項目(在本例中爲字符串)。那麼如何判斷這個子函數需要排序呢?封閉或嵌套功能,非常適合:
def sort_key_factory(start, stop):
def sort_key(string):
return string[start: stop]
return sort_key
簡單的eh?您可以通過在元組或片段對象中封裝開始和停止,然後將這些序列或迭代傳遞給sort_key_factory來擴展此功能。
又一個(非常簡單)的例子。一個返回另一個函數的函數。請注意內部函數(返回的)如何使用外部函數範圍內的變量。
def create_adder(x):
def _adder(y):
return x + y
return _adder
add2 = create_adder(2)
add100 = create_adder(100)
>>> add2(50)
52
>>> add100(50)
150
- 1. 單位對現實世界
- 2. 真實世界的接口實現
- 3. 如何在現實世界中使用函數式編程?
- 4. Exec的現實世界的例子
- 5. 「現實世界」中的功能技巧
- 6. 現實世界的座標骨架
- 7. 仿函數或函數對象的真實世界用法
- 8. 的javascript:在現有的實現嵌套函數
- 9. 你好世界虛擬現實應用
- 10. 實現嵌套GROUP_CONCAT
- 11. 嵌套表實現
- 12. 嵌套棧實現
- 13. 真實世界的目的
- 14. 真實世界中的Glassfish
- 15. 真實世界中的數據結構
- 16. 一種「已排序」數據的現實世界示例
- 17. 現實世界物體之間的四元數差異 - > Unity
- 18. 真實世界的部分函數示例
- 19. 修改現有的嵌套JavaScript函數
- 20. i18n世界您好世界
- 21. C10K爲現代世界
- 22. 嵌套函數
- 23. OOP真實世界示例
- 24. Flashpunk。將實體世界
- 25. 真實世界對象
- 26. RabbitMQ真實世界場景
- 27. 真實世界參數優化
- 28. 關係陣營和「現實世界」數據庫開發
- 29. Microsoft Kinect SDK深度數據到現實世界座標
- 30. 在現實世界中使用核心數據關係嗎?
內部函數是否將封閉範圍內的變量值保留下來,這是事實嗎? – Skilldrick 2010-01-06 23:32:32