Вложенная функция в Python

Какую выгоду или последствия мы можем получить с кодом Python следующим образом:

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

Я нашел это в проекте с открытым исходным кодом, делая что-то полезное внутри вложенной функции, но ничего не делая вне него, кроме как вызывать его. (Фактический код можно найти здесь.) Почему кто-то может его кодировать так? Есть ли какая-то польза или побочный эффект для написания кода внутри вложенной функции, а не во внешней, нормальной функции?

Ответ 1

Обычно вы делаете это, чтобы сделать закрытия:

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

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

Внутренние функции могут обращаться к переменным из охватывающей области (в данном случае локальной переменной x). Если вы не получаете доступ к каким-либо переменным из охватывающей области, они действительно просто обычные функции с другой областью.

Ответ 2

Помимо генераторов функций, где создание внутренней функции является почти определением генератора функций, причиной, по которой я создаю вложенные функции, является улучшение удобочитаемости. Если у меня есть крошечная функция, которая будет вызываться только внешней функцией, тогда я встраиваю определение, поэтому вам не нужно проскакивать, чтобы определить, что делает эта функция. Я всегда могу переместить внутренний метод вне метода инкапсуляции, если я нахожу необходимость повторного использования функции позже.

Пример игрушки:

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

Ответ 3

Одним из потенциальных преимуществ использования внутренних методов является то, что он позволяет использовать внешние переменные внешнего метода, не передавая их в качестве аргументов.

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)

можно записать следующим образом, что, возможно, лучше читается

def save(item, resultBuffer):

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

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

Ответ 4

Я не могу представить, какая из причин для такого кода.

Возможно, была причина для внутренней функции в старых версиях, как и другие Ops.

Например, это имеет несколько большее значение:

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)

но вместо этого внутренняя функция должна быть ("private")):

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

Ответ 5

Идея локальных методов аналогична локальным переменным: не загрязняйте большее пространство имен. Очевидно, что преимущества ограничены, так как большинство языков не предоставляют такую ​​функциональность напрямую.

Ответ 6

Вы уверены, что код был именно таким? Обычная причина делать что-то вроде этого - для создания частичной функции с запекаемыми параметрами. Вызов внешней функции возвращает вызываемый, который не нуждается в параметрах, поэтому его можно хранить и использовать где-то невозможно передать параметры. Однако код, который вы опубликовали, не будет делать это - он немедленно вызывает функцию и возвращает результат, а не вызываемый. Возможно, было бы полезно опубликовать фактический код, который вы видели.