Python中为什么要使用函数嵌套函数?

看一些代码会写成函数中嵌套函数,例如:


 def func():
     def new_func():
          return 1
    a = new_func()

这种写法和 lambda 和单独创建一个 function 有什么区别或优势吗?


Python中为什么要使用函数嵌套函数?
22 回复

嵌套函数在Python里挺常见的,主要就几个实在的用处。

1. 封装与隐藏实现细节 最直接的就是把只在外部函数里用到的逻辑包起来,不污染全局命名空间。比如做个计数器生成器:

def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c = make_counter()
print(c())  # 1
print(c())  # 2

这里的counter函数和count变量在外面都访问不到,干净。

2. 利用闭包保存状态 就像上面例子,内部函数能“记住”外部函数的局部变量(形成闭包),比用类写起来更轻量。

3. 实现装饰器 这是嵌套函数最典型的应用场景了。装饰器本质上就是个返回内部函数的高阶函数:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("函数执行前")
        result = func(*args, **kwargs)
        print("函数执行后")
        return result
    return wrapper

4. 辅助函数与代码组织 在一个复杂的函数里,把一部分逻辑拆成内部函数,能让主流程更清晰,而且这个辅助函数只在这里有用,没必要放外面。

5. 工厂模式与定制行为 外部函数通过参数来定制不同的内部函数并返回,比如:

def power_factory(exponent):
    def power(base):
        return base ** exponent
    return power

square = power_factory(2)
cube = power_factory(3)
print(square(5))  # 25
print(cube(3))    # 27

简单说: 需要隐藏数据、保存状态、写装饰器或者整理代码结构时,嵌套函数就很顺手。

对啊,要写闭包的时候很好用的

查看一下柯里化的定义,这样写返回的新函数能够保持当时的状态,而且能够达到惰性求值的效果(用到这个函数的时候再处理传入的参数)

例如装饰器传参,就是多层嵌套的函数,

因为 lambda 的限制

你的例子确实 lambda 也可以做到。但是下面的呢?

def func(x):
def new_func(y):
return x+y
return new_func

>>> a = func(10)
>>> a(3)
13
>>> a(5)
15

也许是为了方便吧。脚本嘛

额,其实我也不是很了解这两种用法的差异的,不过一不小心就写了出来

In [1]: def func(x):
…: return lambda y:y+x
…:

In [2]: a = func(10)

In [3]: a(3)
Out[3]: 13

In [4]: a(5)
Out[4]: 15

你的例子不合适啊。

>>> a = lambda x: lambda y: x + y
>>> b = a(10)
>>> b(3)
13
>>> b(5)
15

因为 lambda 是匿名的,我想区别应该是名字是否有意义,比如递归吧。

>>> def func(x, sum):
… if(x==0):
… return sum
… return func(x-1, sum + x)

>>> func(10, 0)
55

lambda 大概写不出上面这个递归?

能省几个参数,函数的作用域小了

一般是返回一个函数指针时用。一般外部固定了函数指针的参数,但是自己又需要传递给函数指针一些数据,这样嵌套函数可以使得内部函数可以访问外部函数的变量。关键字:闭包,需求的例子:装饰器。

不用 lambda 的原因是 lambda 限制太大,不方便。

这就是 meta 编程啊

lambda 你能多写几行么

Python 里 lambda 只能写一行啊


需要做到这个的话直接用指针不行吗?

无法实现,像下面的装饰器例子:

https://gist.github.com/GameXG/ed84b114067fb4a7b398cb811a9241ca

需要将 (123) 的 123 传递给 fffff 函数,但是 fffff 函数是会被当作 hello3 参数给用户调用的,用户不会帮你把 123 传递进去,只能通过闭包的方式传递进去 123 .

lambda 写复杂的函数很麻烦啊

这是一种嵌套函数的写法,有时候它和 lambda 没什么区别,但有些情况下它会实现一个闭包,所以我姑且认为楼主是想知道闭包的特性.
那么这里首先强烈建议楼主了解一下 namespace 与变量作用域的相关知识.
http://python.jobbole.com/81367/
如果只要了解闭包的概念,请参考这篇文章.
http://blog.csdn.net/marty_fu/article/details/7679297
如果想知道闭包的实现原理.那么你必须得明白函数调用过程.因为闭包本身就是调用一个函数反回另一个函数.
这里推荐 UCSB 的教程,提供了一个交互式的函数调用演示程序.共6个课程,每个课程都很短,但看完这些你大概能对函数调用帧栈有初步了解.
https://www.cs.ucsb.edu/~pconrad/cs8/topics.beta/theStack/01/
到现在你已经可以开始探究 python 在函数调用中如何精妙地完成参数传递.
http://www.jianshu.com/p/d00108741a18
如果能坚持到这里,那么你已经停不下来了…函数调用过程中所有涉及到的源码作者都给出了分析,看完之后应该什么都明白了
http://python.jobbole.com/83545/
以下链接可以看看,也许能帮助你理解源码.
http://www.cnblogs.com/hackerl/p/5985102.html
http://eli.thegreenplace.net/2012/03/23/python-internals-how-callables-work/

一种劣习,让函数变成有状态的,或者叫不完全依赖于字面输入,还依赖一个隐藏输入的东西

我用这个是因为 有时候要用递归,把 helper 放函数里面可以把外面函数的变量当全局变量。
另外就是 helper 只用这里会用,写外面不清晰。

回到顶部