Python 中的嵌套函数

我们能从这样的 Python 代码中得到什么好处或启示:

class some_class(parent_class):
def doOp(self, x, y):
def add(x, y):
return x + y
return add(x, y)

我在一个开源项目中发现了这一点,它在嵌套函数内部做了一些有用的事情,但是在嵌套函数之外什么也没做,只是调用它。(可以找到实际的代码 给你。)为什么会有人这样编码?将代码写入嵌套函数而不是外部的普通函数,是否有一些好处或副作用?

94843 次浏览

I can't image any good reason for code like that.

Maybe there was a reason for the inner function in older revisions, like other Ops.

For example, this makes slightly more sense:

class some_class(parent_class):
def doOp(self, op, x, y):
def add(x, y):
return x + y
def sub(x,y):
return x - y
return locals()[op](x,y)


some_class().doOp('add', 1,2)

but then the inner function should be ("private") class methods instead:

class some_class(object):
def _add(self, x, y):
return x + y
def doOp(self, x, y):
return self._add(x,y)

The idea behind local methods is similar to local variables: don't pollute the larger name space. Obviously the benefits are limited since most languages don't also provide such functionality directly.

Are you sure the code was exactly like this? The normal reason for doing something like this is for creating a partial - a function with baked-in parameters. Calling the outer function returns a callable that needs no parameters, and so therefore can be stored and used somewhere it is impossible to pass parameters. However, the code you've posted won't do that - it calls the function immediately and returns the result, rather than the callable. It might be useful to post the actual code you saw.

Aside from function generators, where internal function creation is almost the definition of a function generator, the reason I create nested functions is to improve readability. If I have a tiny function that will only be invoked by the outer function, then I inline the definition so you don't have to skip around to determine what that function is doing. I can always move the inner method outside of the encapsulating method if I find a need to reuse the function at a later date.

Toy example:

import sys


def Foo():
def e(s):
sys.stderr.write('ERROR: ')
sys.stderr.write(s)
sys.stderr.write('\n')
e('I regret to inform you')
e('that a shameful thing has happened.')
e('Thus, I must issue this desultory message')
e('across numerous lines.')
Foo()

Normally you do it to make closures:

def make_adder(x):
def add(y):
return x + y
return add


plus5 = make_adder(5)
print(plus5(12))  # prints 17

Inner functions can access variables from the enclosing scope (in this case, the local variable x). If you're not accessing any variables from the enclosing scope, they're really just ordinary functions with a different scope.

One potential benefit of using inner methods is that it allows you to use outer method local variables without passing them as arguments.

def helper(feature, resultBuffer):
resultBuffer.print(feature)
resultBuffer.printLine()
resultBuffer.flush()


def save(item, resultBuffer):


helper(item.description, resultBuffer)
helper(item.size, resultBuffer)
helper(item.type, resultBuffer)

can be written as follows, which arguably reads better

def save(item, resultBuffer):


def helper(feature):
resultBuffer.print(feature)
resultBuffer.printLine()
resultBuffer.flush()


helper(item.description)
helper(item.size)
helper(item.type)

In Python, you can use a nested function to create a decorator like @decorator. *My answer explains more about decorators.

I created multiply_by_5() to use it as the decorator for sum() as shown below:

# (4 + 6) x 5 = 50


def multiply_by_5(func):
def core(*args, **kwargs):
result = func(*args, **kwargs)
return result * 5
return core


@multiply_by_5 # Here
def sum(num1, num2):
return num1 + num2


result = sum(4, 6)
print(result)

Output:

50

The code below is the case of not using the decorator:

# (4 + 6) x 5 = 50


# ...


# @multiply_by_5
def sum(num1, num2):
return num1 + num2


f1 = multiply_by_5(sum) # Here
result = f1(4, 6)
print(result)

Or:

# (4 + 6) x 5 = 50


# ...


# @multiply_by_5
def sum(num1, num2):
return num1 + num2


result = multiply_by_5(sum)(4, 6) # Here
print(result)

Output:

50