Python: альтернатива анонимным функциям - PullRequest
5 голосов
/ 22 января 2012

Python не поддерживает сложные анонимные функции. Какая хорошая альтернатива? Например:

class Calculation:
    def __init__(self, func):
        self.func = func

    def __call__(self, data):
        try:
        # check if the value has already been calculated
        # if it has, it would be cached under key = self.func
            return data[self.func]
        except KeyError:
            pass # first-time call; calculate and cache the values
        data[self.func] = self.func(data)
        return data[self.func]

# with a simple function, which can be represented using lambda, this works great
f1 = Calculation(lambda data : data['a'] * data['b'])

# with a complicated function, I can do this:
def f2_aux:
   # some complicated calculation, which isn't suitable for a lambda one-liner
f2 = Calculation(f2_aux) 

Это разумный дизайн для начала?

Если так, есть ли способ избежать уродства f * _aux для каждого f *, который я определяю в модуле?

UPDATE:

Пример использования:

d = {'a' : 3, 'b' : 6}

# computes 3 * 6
# stores 18 in d under a key <function <lambda> at ...>
# returns 18
f1(d)

# retrieves 18 from d[<function <lambda> at ...>]
# returns 18, without having to recalculate it
f1(d)

UPDATE:

Просто для моего понимания я добавил версию, которая использует внутреннюю функцию.

def memoize(func):
    def new_func(data):
        try:
        # check if the value has already been calculated
        # if it has, it would be cached under key = self.func
            return data[func]
        except KeyError:
            pass # first-time call; calculate and cache the values
        data[func] = func(data)
        return data[func]
    return new_func

@memoize
def f1(data):
  return data['a'] * data['b']

Ответы [ 3 ]

5 голосов
/ 22 января 2012

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

Но чтобы ответить на вопрос: вы можете использовать свой класс в качестве декоратора.

@Calculation
def f2():
    ...

Это просто определило функцию, обернуло ее в Calculation и сохранило результат как f2. Синтаксис декоратора определен, чтобы быть эквивалентным:

_decorator = Calculation # a fresh identifier
# not needed here, but in other cases (think properties) it's useful
def f2():
    ...
f2 = _decorator(f2)
4 голосов
/ 22 января 2012

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

В Python вы создаете анонимные функции с помощью оператора lambda.Например, вы можете сделать это:

output = mysort(input, lambda x: x.lastname)

Лямбда создаст функцию, но у этой функции нет имени в локальном пространстве, и ее собственное имя для себя - просто '<lambda>'.Но если мы посмотрим на mysort, это должно быть определено примерно так:

def mysort(input, getterfunc):
    blahblahblah

Как мы видим здесь, в этом контексте функция вообще не является анонимной.У него есть имя getterfunc.С точки зрения этой функции не имеет значения, является ли переданная функция анонимной или нет.Это работает так же хорошо, и является абсолютно эквивалентным во всех значимых отношениях:

def get_lastname(x):
    return x.lastname

output = mysort(input, get_lastname)

Конечно, он использует больше кода, но он не медленнее или что-то в этом роде.Следовательно, в Python анонимные функции - не что иное, как синтаксический сахар для обычных функций.

По-настоящему анонимная функция будет

lambda x: x.lastname

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

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

1 голос
/ 22 января 2012

Закрытие может быть краткой альтернативой написанию такого класса, как в вашем примере.Техника включает в себя def внутри другого def .Внутренняя функция может иметь доступ к переменной в функции включения.В Python 3 ключевое слово nonlocal дает вам право на запись в эту переменную.В Python 2 вам необходимо использовать изменяемое значение для нелокальной переменной, чтобы иметь возможность обновлять его из внутренней функции.

Что касается вопроса об анонимных функциях, язык намеренно подталкивает вас к использованию def для чего-либо более сложного, чем может выдержать lambda .

...