2010-12-06 3 views
8

Очень редко я сталкиваюсь с некоторым кодом в python, который использует анонимную функцию, которая возвращает анонимную функцию ...?lambda возвращает lambda в python

К сожалению, я не могу найти пример на руке, но она обычно принимает форму, как это:

g = lambda x,c: x**c lambda c: c+1 

Зачем кому-то это сделать? Может быть, вы можете привести пример, который имеет смысл (я не уверен, что тот, который я сделал, имеет какой-то смысл).

Edit: Вот пример:

swap = lambda a,x,y:(lambda f=a.__setitem__:(f(x,(a[x],a[y])), 
     f(y,a[x][0]),f(x,a[x][1])))() 
+3

Найти и показать реальный пример; что он не является синтаксически правильным. – 2010-12-06 00:12:02

+0

создает синтаксис SyntaxError: недопустимый. Нет смысла второй лямбда – joaquin 2010-12-06 00:13:14

+0

Зачем кому-то это делать? Ответ: раздражать других? – joaquin 2010-12-06 00:16:24

ответ

13

Вы можете использовать такую ​​конструкцию, чтобы сделать выделки:

curry = lambda f, a: lambda x: f(a, x) 

Вы можете использовать его как:

>>> add = lambda x, y: x + y 
>>> add5 = curry(add, 5) 
>>> add5(3) 
8 
1

It может быть полезна для временных заполнителей. Предположим, у вас есть декоратора завод:

@call_logger(log_arguments=True, log_return=False) 
def f(a, b): 
    pass 

Вы можете временно заменить его

call_logger = lambda *a, **kw: lambda f: f 

Она также может быть полезным, если оно косвенно возвращает лямбда:

import collections 
collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(int))) 

Это также полезно для создание вызываемых фабрик в консоли Python.

И только потому, что что-то возможно, не означает, что вы должны его использовать.

1

Это можно использовать, чтобы вытащить некоторый общий повторяющийся код (есть, конечно, другие способы достижения этого в python).

Возможно, вы пишете журнал, и вам необходимо добавить уровень в строку журнала. Вы могли бы написать что-то вроде:

import sys 
prefixer = lambda prefix: lambda message: sys.stderr.write(prefix + ":" + message + "\n") 
log_error = prefixer("ERROR") 
log_warning = prefixer("WARNING") 
log_info = prefixer("INFO") 
log_debug = prefixer("DEBUG") 

log_info("An informative message") 
log_error("Oh no, a fatal problem") 

Эта программа печатает

INFO:An informative message 
    ERROR:Oh no, a fatal problem 
1

я сделал что-то вроде этого только другой день, чтобы отключить тестовый метод в UnitTest люкс.

disable = lambda fn : lambda *args, **kwargs: None 

@disable 
test_method(self): 
    ... test code that I wanted to disable ... 

Легко восстановить его позже.

2
swap = lambda a,x,y:(lambda f=a.__setitem__:(f(x,(a[x],a[y])), 
     f(y,a[x][0]),f(x,a[x][1])))() 

Просмотреть() в конце? Внутренняя лямбда не возвращается, ее зовут.

Функция делает эквивалент

def swap(a, x, y): 
    a[x] = (a[x], a[y]) 
    a[y] = a[x][0] 
    a[x] = a[x][1] 

Но давайте предположим, что мы хотим сделать это в лямбда. Мы не можем использовать назначения в лямбда. Однако мы можем назвать __setitem__ для того же эффекта.

def swap(a, x, y): 
    a.__setitem__(x, (a[x], a[y])) 
    a.__setitem__(y, a[x][0]) 
    a.__setitem__(x, a[x][1]) 

Но для лямбда мы можем иметь только одно выражение. Но так как эти вызовы функций мы можем обернуть их в кортеже

def swap(a, x, y): 
    (a.__setitem__(x, (a[x], a[y])), 
    a.__setitem__(y, a[x][0]), 
    a.__setitem__(x, a[x][1])) 

Однако все эти __setitem__ «s получают меня, так что давайте учитывать их:

def swap(a, x, y): 
    f = a.__setitem__ 
    (f(x, (a[x], a[y])), 
    f(y, a[x][0]), 
    f(x, a[x][1])) 

Dagnamit, я могу «Убирайтесь с добавлением другого задания! Я знаю, что давайте использовать параметры по умолчанию.

def swap(a, x, y): 
    def inner(f = a.__setitem__): 
     (f(x, (a[x], a[y])), 
     f(y, a[x][0]), 
     f(x, a[x][1])) 
    inner() 

Хорошо давайте перейдем к лямбды:

swap = lambda a, x, y: lambda f = a.__setitem__: (f(x, (a[x], a[y])), f(y, a[x][0]), f(x, a[x][1]))() 

Что возвращает нас к исходному выражению (плюс/минус опечаток)

Все это приводит к вопросу: Зачем?

функция должна быть реализована в виде

def swap(a, x, y): 
    a[x],a[y] = a[y],a[x] 

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

0

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

Например, если я хочу, чтобы создать список из десяти функций, каждая из которых множитель для скаляра от 0 до 9. Один может возникнуть соблазн написать это:

>>> a = [(lambda j: i * j) for i in range(10)] 
>>> a[9](10) 
90 

Кто, если вы хотите использовать какой-либо из других факторизованных функций вы получите тот же результат:

>>> a[1](10) 
90 

это происходит потому, что «я» переменный внутри лямбда не решен при создании лямбды. Скорее, Python сохраняет ссылку на «i» в выражении «for» - в области, которую он создал (эта ссылка хранится в закрытии лямбда-функции). Когда lambda выполняется, переменная оценивается, и ее значение является окончательным, которое было в этой области.

Когда один использует два вложенных лямбды как это:

>>> a = [(lambda k: (lambda j: k * j))(i) for i in range(10)] 

«Я» переменная оценены durint выполнения «для» петли. Значение Itś передается в «k» - и «k» используется как нелокальная переменная в множительной функции, которую мы факторизуем. Для каждого значения i будет другой экземпляр входящей лямбда-функции и другое значение для переменной «k».

Таким образом, можно достичь первоначальной цели:

>>> a = [(lambda k: (lambda j: k * j))(i) for i in range(10)] 
>>> a[1](10) 
10 
>>> a[9](10) 
90 
>>> 
0

Он может быть использован для достижения более продолжения/батут стиля программирования,

Посмотреть Continuation-passing style