这个Python函数发生了什么?

时间:2014-07-30 05:08:58

标签: python

def function(a):
    def f1(a, b): a[b] = (a.get(b) or 0) + 1; return a
    return map(lambda a: a[0], filter(lambda a: not a[1] == 1,
               reduce(f1, a, {}).items()))

我已尝试打印此功能的返回值。当我为'a'分配一个数字时没有打印,如果我将一个字符串分配给'a',该函数返回一个由逗号分隔的随机字母列表。除此之外,我不确定发生了什么或为什么要打印这些字母。希望比我更聪明的人能够看到这一点,并了解正在发生的事情。

另外,这被认为是更高阶函数吗?

1 个答案:

答案 0 :(得分:7)

此代码看起来有意混淆;希望它在生产中不存在。对变量名称的长度或行数没有征税。

那就是说,了解它你只需要将其分解一下。我们有:

return map(lambda a: a[0],               # extract the first element
        filter(lambda a: not a[1] == 1,  # take iff second element != 1
           reduce(f1, a, {}).items()     # reduce a using f1, then take items()
         )
    )

因此,换句话说,结果将是通过运行reduce(f1, a, {})构建的字典中的每个键,其对应值不是1

我们现在可以考虑这里实际发生了什么。

def f1(a, b):
    a[b] = (a.get(b) or 0) + 1
    return a

当作为参数传递给reduce时,f1的第一个参数将是正在构建的序列,第二个参数将是正在处理的项。

这里讨论的序列是一个字典(您可以从reduce的参数以及在a.get中使用f1来判断。考虑到这一点:

def f1(a, b):
    a[b] = (a.get(b) or 0) + 1  # increment value iff key present else value=1
    return a                    # return mutated sequence

因此,运行reduce(f1, 'some_string', {})的结果将是一个字典,将字符映射到字符串中的频率。

整个函数因此返回在字符串中出现多次的所有字母。


问题中的功能显然是一个人为的例子;考虑更好的方法来做到这一点是很简单的(地狱,很难想到更糟糕的)。

一种可能的解决方案,虽然绝不是最好的解决方案,但是会像:

freqs = lambda s: [c for c in set(s) if s.count(c) > 1]

或者,如果你真的喜欢使用mapfilter,你可以这样做:

freqs = lambda s: filter(lambda count: count > 1, map(s.count, set(s))

老实说,这是一个案例,其中列表推导的python仍然 更具可读性;以上就像地狱一样拙劣和丑陋。