当只需要一个函数时,嵌套函数是一种好的方法吗?

假设 function A仅仅是 function B所需要的,那么 A 应该定义在 B 中吗?

简单的例子。两个方法,一个从另一个调用:

def method_a(arg):
some_data = method_b(arg)


def method_b(arg):
return some_data

在 Python 中,我们可以在另一个 def中声明 def。那么,如果 method_b是必需的并且只能从 method_a调用,我是否应该在 method_a中声明 method_b?像这样:

def method_a(arg):
    

def method_b(arg):
return some_data


some_data = method_b(arg)

或者我应该避免这样做?

260368 次浏览
>>> def sum(x, y):
...     def do_it():
...             return x + y
...     return do_it
...
>>> a = sum(1, 3)
>>> a
<function do_it at 0xb772b304>
>>> a()
4

- 这就是你要找的?-这叫 了结

实际上,在另一个函数中声明一个函数是很好的,这对于创建装饰符特别有用。

但是,根据经验,如果函数很复杂(超过10行) ,最好在模块级别声明它。

这样做并没有什么好处,实际上它会降低 method_a的速度,因为每次调用它时,它都会定义并重新编译另一个函数。考虑到这一点,最好只在函数名前加下划线,以表明它是一个私有方法——也就是 _method_b

如果嵌套函数的定义由于某种原因每次都有变化,那么我认为 也许吧希望这样做,但这可能表明您的设计存在缺陷。也就是说,有一个合理的理由允许嵌套函数使用传递给外部函数但没有显式传递给它们的参数,例如,在编写函数修饰符时有时会出现这种情况。尽管没有定义或使用装饰器,但它是在可接受的答案中显示的。

更新:

下面的例子证明了嵌套它们的速度更慢(使用 Python 3.6.1) ,尽管在这个小案例中显然不是很快:

setup = """
class Test(object):
def separate(self, arg):
some_data = self._method_b(arg)


def _method_b(self, arg):
return arg+1


def nested(self, arg):


def method_b2(self, arg):
return arg+1


some_data = method_b2(self, arg)


obj = Test()
"""
from timeit import Timer
print(min(Timer(stmt='obj.separate(42)', setup=setup).repeat()))  # -> 0.24479823284461724
print(min(Timer(stmt='obj.nested(42)', setup=setup).repeat()))    # -> 0.26553459700452575

注意,我在示例函数中添加了一些 self参数,使它们更像真正的方法(尽管从技术上讲,method_b2仍然不是 Test类的方法)。另外,嵌套函数实际上是在那个版本中调用的,不像您的版本。

这样做是完全可以的,但是除非您需要使用闭包或返回函数,否则我可能会放在模块级别中。我想在第二个代码示例中,您的意思是:

...
some_data = method_b() # not some_data = method_b

否则,some _ data 将成为函数。

在模块级别使用它将允许其他函数使用 method _ b () ,如果您使用类似于 狮身人面像(和 autodoc)的东西来编写文档,那么它也将允许您编写 method _ b 文档。

如果您所做的事情可以由对象表示,那么您也可以考虑将功能放在类中的两个方法中。如果这就是你想要的,这也包含了很好的逻辑。

这只是暴露 API 的一个原则。

使用 python 是一个避免在外部空间(模块或类)暴露 API 的好主意,函数是一个很好的封装场所。

这可能是一个好主意。当你确保

  1. 内部函数是外部函数使用的 仅此而已
  2. 内部函数有一个 很好名称来解释它的用途,因为代码会说话。
  3. 代码不能被同事(或其他代码阅读器)直接理解。

尽管如此,滥用这种技术可能会导致问题,并意味着设计缺陷。

从我的经验来看,也许误解了你的问题。

比如:

def some_function():
return some_other_function()
def some_other_function():
return 42

如果你运行 some_function(),它会运行 some_other_function()并返回42。

编辑: 我最初说过,不应该在另一个函数中定义一个函数,但是有人指出,有时候这样做是可行的。

函数内部的函数通常用于 关闭

(在 到底是什么上有一个 很多争论使得 结束,结束。)

下面是一个使用内置 sum()的例子,它定义了 start一次,并从此开始使用它:

def sum_partial(start):
def sum_start(iterable):
return sum(iterable, start)
return sum_start

使用中:

>>> sum_with_1 = sum_partial(1)
>>> sum_with_3 = sum_partial(3)
>>>
>>> sum_with_1
<function sum_start at 0x7f3726e70b90>
>>> sum_with_3
<function sum_start at 0x7f3726e70c08>
>>> sum_with_1((1,2,3))
7
>>> sum_with_3((1,2,3))
9

内置的 Python 闭包

functools.partial 是闭包的一个例子。

从 python docs 来看,它大致相当于:

def partial(func, *args, **keywords):
def newfunc(*fargs, **fkeywords):
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*(args + fargs), **newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc

(以下是@user225312的答案。我发现这个例子更容易理解,并且希望能够帮助回答@Mango 的评论。)

我发现这个问题是因为我想提出一个问题,如果使用嵌套函数,为什么会对性能产生影响。我使用 Python 3.2.5在装有 Quad Core 2.5 GHz Intel i5-2530M 处理器的 Windows 笔记本电脑上运行了以下函数的测试

def square0(x):
return x*x


def square1(x):
def dummy(y):
return y*y
return x*x


def square2(x):
def dummy1(y):
return y*y
def dummy2(y):
return y*y
return x*x


def square5(x):
def dummy1(y):
return y*y
def dummy2(y):
return y*y
def dummy3(y):
return y*y
def dummy4(y):
return y*y
def dummy5(y):
return y*y
return x*x

我测量了下面的20次,同样是1,2和5的平方:

s=0
for i in range(10**6):
s+=square0(i)

结果如下

>>>
m = mean, s = standard deviation, m0 = mean of first testcase
[m-3s,m+3s] is a 0.997 confidence interval if normal distributed


square? m     s       m/m0  [m-3s ,m+3s ]
square0 0.387 0.01515 1.000 [0.342,0.433]
square1 0.460 0.01422 1.188 [0.417,0.503]
square2 0.552 0.01803 1.425 [0.498,0.606]
square5 0.766 0.01654 1.979 [0.717,0.816]
>>>

square0没有嵌套函数,square1有一个嵌套函数,square2有两个嵌套函数,square5有五个嵌套函数。只声明嵌套函数,而不调用它们。

所以如果你在一个函数中定义了5个没有调用的嵌套函数,那么这个函数的执行时间是没有嵌套函数的函数的两倍。我认为在使用嵌套函数时应该小心谨慎。

生成这个输出的整个测试的 Python 文件可以在 想法中找到。

所以最后,这在很大程度上是一个关于 python 实现是否聪明的问题,特别是在内部函数不是闭包而只是一个只需要 helper 的 in 函数的情况下。

在简洁易懂的设计中,只在需要的地方使用函数而不在其他地方公开函数,无论是将函数嵌入到模块、类作为方法,还是嵌入到另一个函数或方法中,都是好的设计。当做得好的时候,它们确实提高了代码的清晰度。

如果内部函数是一个闭包,那么即使该函数没有从包含函数返回到其他地方使用,这个闭包也可以大大提高清晰度。

因此,我认为通常应该使用它们,但是在实际关心性能时要注意可能对性能造成的影响,并且只有在进行实际分析显示最好删除它们的情况下才删除它们。

不要在编写的所有 Python 代码中过早地使用“内部函数 BAD”进行优化。

通常,不要在函数中定义函数。

除非你有很好的理由,但你没有。

为什么不呢?

什么样的 才是在函数内部定义函数的真正好理由?

当你想要的是一个叮当 [关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关闭][关

您可以使用它来避免定义全局变量。这为其他设计提供了另一种选择。3个设计提出了一个问题的解决方案。

A)使用不带全局变量的函数

def calculate_salary(employee, list_with_all_employees):
x = _calculate_tax(list_with_all_employees)


# some other calculations done to x
pass


y = # something


return y


def _calculate_tax(list_with_all_employees):
return 1.23456 # return something

B)使用带有全局变量的函数

_list_with_all_employees = None


def calculate_salary(employee, list_with_all_employees):


global _list_with_all_employees
_list_with_all_employees = list_with_all_employees


x = _calculate_tax()


# some other calculations done to x
pass


y = # something


return y


def _calculate_tax():
return 1.23456 # return something based on the _list_with_all_employees var

C)在另一个函数中使用函数

def calculate_salary(employee, list_with_all_employees):


def _calculate_tax():
return 1.23456 # return something based on the list_with_a--Lemployees var


x = _calculate_tax()


# some other calculations done to x
pass
y = # something


return y

解决方案 C)允许在外部函数的作用域中使用变量,而不需要在内部函数中声明它们。在某些情况下可能有用。

函数中的函数

def Greater(a,b):
if a>b:
return a
return b


def Greater_new(a,b,c,d):
return Greater(Greater(a,b),Greater(c,d))


print("Greater Number is :-",Greater_new(212,33,11,999))