我之前问过nested functions是如何工作的,但遗憾的是我还是不太明白。为了更好地理解它,有人可以展示一些嵌套函数的实际用法示例吗?
非常感谢
答案 0 :(得分:10)
你的问题让我很好奇,所以我查看了一些真实的代码: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
希望你传递一个事件处理函数,所以我们定义一个并传递它。
答案 1 :(得分:8)
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__
答案 2 :(得分:4)
嵌套函数可以避免使用其他只在本地有意义的函数和变量来混淆程序的其他部分。
返回Fibonacci数的函数可以定义如下:
>>> 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]
编辑:在实践中,生成器将是一个更好的解决方案,但该示例显示了如何利用嵌套函数。
答案 3 :(得分:2)
我只需要在创建装饰器时使用嵌套函数。嵌套函数基本上是一种向函数添加某些行为的方法,而不知道您要添加行为的函数是什么。
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”函数中的所有mumbo jumbo,并仅关注“sayHello”函数及其下方。我们在这里做的是我们想要打印出如何调用“sayHello”函数,而不知道或改变“sayHello”函数的作用。所以我们通过将“sayHello”函数传递给“printCall”来重新定义它,该函数返回一个新函数,它执行“sayHello”函数的工作并打印出如何调用“sayHello”函数。这是装饰者的概念。
将“@printCall”放在sayHello定义之上可以完成同样的事情:
@printCall
def sayHello(name):
print "Hello, my name is %s" % (name)
if __name__ == "__main__":
name = "Nimbuz"
sayHello(name)
答案 4 :(得分:2)
当使用将其他函数作为输入的函数时,它们很有用。假设你在一个函数中,并希望根据dict中项目的值对项目列表进行排序:
def f(items):
vals = {}
for i in items: vals[i] = random.randint(0,100)
def key(i): return vals[i]
items.sort(key=key)
你可以在那里定义键并使用 vals ,一个局部变量。
另一个用例是回调。
答案 5 :(得分:2)
又一个(非常简单)的例子。返回另一个函数的函数。注意内部函数(返回的)如何使用外部函数范围内的变量。
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
答案 6 :(得分:1)
这实际上是另一个要学习的主题,但如果你看一下“使用函数作为装饰器”的内容,你会看到一些嵌套函数的例子。
答案 7 :(得分:1)
好的,除了装饰器:假设你有一个应用程序,你需要根据不时变化的子串对字符串列表进行排序。现在sorted
函数采用key=
参数,该参数是一个参数的函数:要排序的项(在本例中为字符串)。那么如何告诉这个函数哪个子串排序呢?闭包或嵌套函数是完美的:
def sort_key_factory(start, stop):
def sort_key(string):
return string[start: stop]
return sort_key
简单呃?您可以通过在元组或切片对象中封装start和stop,然后将这些序列或者iterable传递给sort_key_factory来扩展它。