Как может работать этот функциональный код python?
-
13-09-2019 - |
Вопрос
это взято из исходного кода csv2rec в matplotlib
как может работать эта функция, если ее единственными параметрами являются 'func, default'?
def with_default_value(func, default):
def newfunc(name, val):
if ismissing(name, val):
return default
else:
return func(val)
return newfunc
ismissing принимает имя и значение и определяет, должна ли строка быть замаскирована в массиве numpy.
функция будет либо иметь значение str, int, float, либо dateparser...it преобразует данные.Может быть, и не важно.Мне просто интересно, как он может получить "имя" и "значение"
Я новичок.Спасибо за любые 2цента!Я надеюсь стать достаточно хорошим, чтобы помогать другим!
Решение
Это with_default_value
функция - это то, что часто называют (неточно) "замыканием" (технически, замыкание - это скорее внутренний функция, которая возвращается, здесь newfunc
-- см . , например , здесь).В более общем смысле, with_default_value
является функция более высокого порядка ("HOF"):для этого требуется функция (func
) в качестве аргумента он также возвращает функцию (newfunc
) в результате.
Я видел ответы, путающие это с декоратор концепция и конструкция на Python, которая определенно не по делу - особенно после того , как вы упомянули func
так же часто являясь встроенным, таким как int
.Декораторы также являются функциями более высокого порядка, но довольно специфичными:те, которые возвращают оформленный, т. е."обогащенная" версия аргумента их функции (которая должна быть Только аргумент - "декораторы с аргументами" получаются через еще один уровень вложенности функции / замыкания, не предоставляя декоратору более одного аргумента), которому присваивается точно такое же имя, что и у этого аргумента функции (и поэтому обычно имеет ту же подпись - использование декоратора в противном случае было бы чрезвычайно своеобразный, неидиоматичный, нечитаемый и т.д.).
Поэтому забудьте о декораторах, которые не имеют абсолютно никакого отношения к делу, и сосредоточьтесь на newfunc
завершение.Лексически вложенная функция может ссылаться (хотя и не привязывать повторно) на все имена локальных переменных (включая имена аргументов, поскольку аргументы являются локальными переменными) заключающей функции (ов) - вот почему она известна как замыкание:он "закрыт" над этими "свободными переменными".Здесь, newfunc
может ссылаться на func
и default
-- и делает.
Функции более высокого порядка - очень естественная вещь в Python, особенно с учетом того, что функции являются объектами первого класса (поэтому вам не нужно ничего особенного делать, чтобы передавать их в качестве аргументов, возвращать их как значения функции или даже хранить их в списках или других контейнерах и т.д.), И нет различия в пространстве имен между функциями и другими типами объектов, нет автоматического вызова функций только потому, что они упомянуты, и т.д. и т.п.(Это сложнее - немного сложнее или НАМНОГО сложнее, в зависимости от того - в других языках, которые проводят множество различий такого рода).В Python упоминание функции - это просто упоминание;вызов выполняется только в том случае, если за объектом функции (на который ссылаются по имени или иным образом) следуют круглые скобки.
Вот, пожалуй, и все, что есть в этом примере - пожалуйста, не стесняйтесь редактировать свой вопрос, комментировать здесь и т.д., если есть какой-то другой конкретный аспект, в котором вы по-прежнему сомневаетесь!
Редактировать:итак, ОП вежливо прокомментировала ситуацию, попросив привести еще примеры "фабрик закрытия".Вот один из них - представьте себе какой-то абстрактный набор инструментов GUI, и вы пытаетесь сделать:
for i in range(len(buttons)):
buttons[i].onclick(lambda: mainwin.settitle("button %d click!" % i))
но это работает неправильно -- i
в пределах lambda
привязан к концу, поэтому к моменту нажатия одной кнопки i
значением s всегда будет индекс Последние кнопка, независимо от того, какая из них была нажата.Существуют различные возможные решения, но укупорочная фабрика - это элегантная возможность:
def makeOnclick(message):
return lambda: mainwin.settitle(message)
for i in range(len(buttons)):
buttons[i].onclick(makeOnClick("button %d click!" % i))
Здесь мы используем фабрику закрытия, чтобы настроить время привязки переменных!-) В той или иной конкретной форме это довольно распространенный вариант использования для фабрик закрытия.
Другие советы
Это декоратор Python - по сути, оболочка функции.(Читайте все о декораторах в PEP 318 -- http://www.python.org/dev/peps/pep-0318/)
Если вы просмотрите код, вы, вероятно, найдете что-то вроде этого:
def some_func(name, val):
# ...
some_func = with_default_value(some_func, 'the_default_value')
Намерение этого декоратора, по-видимому, предоставить значение по умолчанию, если отсутствуют аргументы name или val (предположительно, если для них установлено значение None).
Что касается того, почему это работает:
with_default_value возвращает объект функции, который в основном будет Копировать из этого вложенного newfunc, с вызовом 'func' и значением по умолчанию, замененным тем, что было передано в with_default_value .
Если кто-то сделает 'foo = with_default_value(bar, 3)', возвращаемое значение в основном будет новой функцией:
def foo(name, val):
ifismissing(name, val):
return 3
else:
return bar(val)
таким образом, затем вы можете взять это возвращаемое значение и вызвать его.
Это функция, которая возвращает другую функцию. name
и value
являются параметрами возвращаемой функции.