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