python:匿名函数的替代品

时间:2012-01-22 07:34:58

标签: python lambda python-3.x anonymous-function

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 *的f * _aux的丑陋?

更新:

使用示例:

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)

更新:

仅仅为了我的理解,我添加了一个使用内部函数的版本。

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 个答案:

答案 0 :(得分:5)

您不需要匿名功能。此外,记忆已经做得比这更好,你可能没有理由自己动手。

但要回答这个问题:你可以将你的班级用作装饰师。

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

答案 1 :(得分:4)

匿名函数的替代方法是非匿名函数。匿名函数仅在定义它的上下文中是匿名的。但它不是真正的匿名,因为那时你无法使用它。

在Python中,您使用lambda语句创建匿名函数。例如,你可以这样做:

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

lambda将创建一个函数,但该函数在本地空间中没有名称,并且它自己的名称只是'<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

但是由于我们没有将结果函数分配给任何东西,我们没有获得该函数的名称,然后我们无法使用它。所有真正的匿名函数都无法使用。

因此,如果您需要一个不能是lambda的函数,请将其设为普通函数。它永远不会以任何有意义的方式匿名,所以为什么要打扰匿名呢?当你想要一个小的单行函数并且你不想通过定义一个完整的函数来浪费空间时,Lambdas非常有用。他们是匿名的是无关紧要的。

答案 2 :(得分:1)

闭包可以是编写类(例如示例中的类)的简洁替代方法。该技术涉及将 def 放在另一个 def 中。内部函数可以访问封闭函数中的变量。在Python 3中, nonlocal 关键字为您提供对该变量的写入权限。在Python 2中,您需要为非局部变量使用可变值,以便能够从内部函数更新它。

关于匿名函数的问题,该语言有意将您推回使用 def ,而不是 lambda 可以处理的任何事情。