何时在函数内部创建嵌套函数以及何时从外部调用它?
When to create a nested function inside a function and when to call it from outside?
我看过一些具有这些结构的代码。
结构一:函数内创建内部函数
def external_func(num):
def internal_func(num2):
return num2*2
return internal_func(num + 10)
test = external_func(5)
print(test)
结构 2:一个函数正在调用自身外部的另一个函数。
def _internal_func2(num2):
return num2 * 2
def external_func2(num):
return _internal_func2(num + 10)
test2 = external_func2(5)
print(test2)
对于这种特殊情况,两个函数提供相同的输出。我应该在哪里以及为什么要使用这些结构中的每一个?
结构 1 的主要优点之一是它使 internal_func
局部作用于 external_func
。换句话说,您明确表示 internal_func
应该 仅 被 external_func
访问。就像 external_func
中定义的任何其他常规变量一样对待它。类似于没有分散的全局变量,有时你想“隐藏”其他函数中的实现。
然后您可以在其他方法中使用其他类似名称的 internal_func
,并且它们的名称不会冲突:
In [39]: def external_func_x2(num):
...: def f():
...: return num * 2
...: return internal_func
...:
In [40]: def external_func_x3(num):
...: def f():
...: return num * 3
...: return internal_func
一个常见的目的是制作根据特定条件生成其他函数的函数:
In [44]: def make_multiplier(mult):
...: def f(num):
...: return num*mult
...: return f
...:
In [45]: x4 = make_multiplier(4)
In [46]: x4(8)
Out[46]: 32
In [47]: x3 = make_multiplier(3)
In [48]: x3(8)
Out[48]: 24
您可以使用结构 2(或 functools.partial
)执行与上面相同的示例,但这样会降低可读性,并且您需要在外部公开此内部 f
函数scope/namespace,即使它只被 make_multiplier
方法使用。同样,将其想象成将方法隐藏在 class 中。您还必须将参数从一个函数传递到另一个函数,而不是像我们在结构 1 中那样使用闭包。
如果您将此 make_multiplier
作为某些 library/API 的一部分,使用结构 1“隐藏”此 f
函数并使其更清晰,更易读 [= library/API 的 57=],他们只需要“查看”make_multiplier
方法。
还有一个关于可维护性的争论。如果您需要修改 make_multiplier
,很明显您需要修改 f
,并且您可以非常确定修改 f
不会破坏代码的其他部分,因为没有人使用它而不是 make_multiplier
.
结构 2 是您“将大功能拆分为更小、更易于管理和可重用的功能”的标准良好实践。与 Structure 1 相比,它的主要优点是可测试性和可重用性。直接测试和模拟 _internal_func2
更容易,而不需要调用 external_func2
,如果 external_func2
本身调用起来特别复杂,这很好。编写直接针对嵌套内部函数的测试也非常困难。
它也使得 _internal_func2
可以被其他方法重用。将其与上面结构 1 的示例进行比较,如果您发现自己编写的相同内部 f
嵌套在许多 external_func
中,那么最好将其移出并转换为结构 2 样式。
我看过一些具有这些结构的代码。
结构一:函数内创建内部函数
def external_func(num):
def internal_func(num2):
return num2*2
return internal_func(num + 10)
test = external_func(5)
print(test)
结构 2:一个函数正在调用自身外部的另一个函数。
def _internal_func2(num2):
return num2 * 2
def external_func2(num):
return _internal_func2(num + 10)
test2 = external_func2(5)
print(test2)
对于这种特殊情况,两个函数提供相同的输出。我应该在哪里以及为什么要使用这些结构中的每一个?
结构 1 的主要优点之一是它使 internal_func
局部作用于 external_func
。换句话说,您明确表示 internal_func
应该 仅 被 external_func
访问。就像 external_func
中定义的任何其他常规变量一样对待它。类似于没有分散的全局变量,有时你想“隐藏”其他函数中的实现。
然后您可以在其他方法中使用其他类似名称的 internal_func
,并且它们的名称不会冲突:
In [39]: def external_func_x2(num):
...: def f():
...: return num * 2
...: return internal_func
...:
In [40]: def external_func_x3(num):
...: def f():
...: return num * 3
...: return internal_func
一个常见的目的是制作根据特定条件生成其他函数的函数:
In [44]: def make_multiplier(mult):
...: def f(num):
...: return num*mult
...: return f
...:
In [45]: x4 = make_multiplier(4)
In [46]: x4(8)
Out[46]: 32
In [47]: x3 = make_multiplier(3)
In [48]: x3(8)
Out[48]: 24
您可以使用结构 2(或 functools.partial
)执行与上面相同的示例,但这样会降低可读性,并且您需要在外部公开此内部 f
函数scope/namespace,即使它只被 make_multiplier
方法使用。同样,将其想象成将方法隐藏在 class 中。您还必须将参数从一个函数传递到另一个函数,而不是像我们在结构 1 中那样使用闭包。
如果您将此 make_multiplier
作为某些 library/API 的一部分,使用结构 1“隐藏”此 f
函数并使其更清晰,更易读 [= library/API 的 57=],他们只需要“查看”make_multiplier
方法。
还有一个关于可维护性的争论。如果您需要修改 make_multiplier
,很明显您需要修改 f
,并且您可以非常确定修改 f
不会破坏代码的其他部分,因为没有人使用它而不是 make_multiplier
.
结构 2 是您“将大功能拆分为更小、更易于管理和可重用的功能”的标准良好实践。与 Structure 1 相比,它的主要优点是可测试性和可重用性。直接测试和模拟 _internal_func2
更容易,而不需要调用 external_func2
,如果 external_func2
本身调用起来特别复杂,这很好。编写直接针对嵌套内部函数的测试也非常困难。
它也使得 _internal_func2
可以被其他方法重用。将其与上面结构 1 的示例进行比较,如果您发现自己编写的相同内部 f
嵌套在许多 external_func
中,那么最好将其移出并转换为结构 2 样式。