如果函数A只被函数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_a ? 喜欢这个 :

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

或者我应该避免这样做?

 >>> 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 

这是你在找什么? 这就是所谓的封闭 。

这样做并没有真正获益,事实上,它会减慢method_a速度,因为每次调用时都会定义和重新编译其他函数。 鉴于此,只需在函数名称前加下划线来表示它是一个私有方法,也就是_method_b

我想如果嵌套函数的定义因为某种原因每次都有所不同,你可能会想要这样做,但是这可能表明你的devise有缺陷。 也就是说,有一个合理的理由来允许嵌套函数使用传递给外部函数的参数,而不是显式传递给它们,例如,在编写函数装饰器时会发生这种情况。 这是接受的答案中显示的内容,尽pipe装饰器没有被定义或使用。

更新:

嵌套它们的速度比较慢(使用Python 3.6.1),尽pipe在这个微不足道的例子中并没有太多的说明:

 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参数,使它们更像真正的方法(尽pipemethod_b2仍然不是Test类的方法)。 此外,嵌套函数实际上是在该版本中调用,不像你的。

函数内部的函数通常用于闭包 。

(关于什么是 闭包,关于闭包有很多争论 。)

这是一个使用内置sum()的例子。 它定义了一次start并从此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文档 ,它大致相当于:

 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的评论。)

在另一个函数中声明一个函数其实很好。 这是创build装饰器特别有用。

但是,作为一个经验法则,如果函数是复杂的(超过10行),在模块级上声明它可能是一个更好的主意。

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

 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次,也是square1,square2和square5:

 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? msm/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个嵌套函数,那么函数的执行时间就是没有嵌套函数的函数的两倍。 我认为使用嵌套函数时应该谨慎。

生成此输出的整个testing的Python文件可以在ideone中find。

一般来说不,不要在函数内部定义函数。

除非你有一个很好的理由。 你不这样做。

为什么不?

  • 它可以防止简单的钩子进行unit testing。 你是unit testing,不是吗?
  • 它实际上并不完全混淆它 ,因此在python中没有任何事情是安全的。
  • 使用标准的Python自动化代码风格指南来封装方法。
  • 每次运行外部函数时,都会不必要地为相同的代码重新创build一个函数对象 。
  • 如果你的函数真的很简单, 你应该使用lambdaexpression式来代替 。

在函数内部定义函数的真正原因什么?

当你真正想要的是一个当当closures

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

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

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

  1. 内部函数被外部函数使用。
  2. 内幕函数有一个很好的名字来解释它的目的,因为代码会谈。
  3. 代码不能被你的同事(或其他代码阅读器)直接理解。

即使滥用这种技术可能会导致问题,并意味着devise缺陷。

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

所以最后,主要是关于python实现是多么聪明的一个问题,特别是在内部函数不是闭包的情况下,而只是一个函数只需要帮助程序。

在干净可理解的devise中,只有在需要而不在别处暴露的情况下才具有function,不pipe是embedded模块,作为方法的类还是其他function或方法的embedded都是很好的devise。 如果做得好,他们真的可以提高代码的清晰度。

而且,当内部函数是一个闭包时,即使该函数没有从包含函数中返回以供其他地方使用,也可以帮助澄清相当多的内容。

所以我通常会说使用它们,但是当你真正关心性能时要注意可能的性能,只有在你做了实际的性能分析时才去除它们,这表明它们最好被移除。

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

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

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

否则,some_data就是这个函数。

在模块级别使用它将允许其他函数使用method_b(),如果您使用的是Sphinx (和autodoc)来进行文档化,它也将允许您loggingmethod_b。

如果你正在做一些可以被对象表示的东西,你也可以考虑把这个function放在类中的两个方法中。 这也包含逻辑,如果这就是你想要的。

MDDL的答案没有为我工作。

这样做:

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

做类似的事情:

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

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

编辑:我原来说,你不应该在另一个里面定义一个函数,但有人指出,有时这样做是实际的。