如何在 Python 3 中使用 filter、map 和 Reduce

2024-12-17 08:30:00
admin
原创
158
摘要:问题描述:这是我在 Python 2 中习惯使用filter、map和 的工作方式:reduce>>> def f(x): return x % 2 != 0 and x % 3 != 0 >>> filter(f, range(2, 25)) [5, 7,...

问题描述:

这是我在 Python 2 中习惯使用filtermap和 的工作方式:reduce

>>> def f(x):
        return x % 2 != 0 and x % 3 != 0
>>> filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]

>>> def cube(x):
        return x*x*x
>>> map(cube, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

>>> def add(x,y):
        return x+y
>>> reduce(add, range(1, 11))
55

然而,所有这些似乎在 Python 3 中都失效了:

>>> filter(f, range(2, 25))
<filter object at 0x0000000002C14908>

>>> map(cube, range(1, 11))
<map object at 0x0000000002C82B70>

>>> reduce(add, range(1, 11))
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    reduce(add, range(1, 11))
NameError: name 'reduce' is not defined

为什么结果不同?如何让 Python 3 代码像 Python 2 代码一样工作?


另请参阅:reduce() 有什么问题?reduce了解将其放入标准库模块而不是将其保留为内置模块的具体动机。

有关更具体的答案,请参阅在 Python 3.x 中获取 map() 以返回列表map


解决方案 1:

您可以在 Python 3.0 的新增功能中了解这些变化。从 2.x 升级到 3.x 时,您应该仔细阅读它,因为有很多变化。

这里的全部答案均来自文档的引用。

使用视图和迭代器代替列表

一些众所周知的 API 不再返回列表:

  • [...]

  • map()filter()返回迭代器。如果您确实需要列表,那么快速修复方法是例如list(map(...)),但更好的修复方法通常是使用列表推导(尤其是当原始代码使用 lambda 时),或者重写代码,使其根本不需要列表。特别棘手的是map()调用函数的副作用;正确的转换是使用常规for循环(因为创建列表只会浪费时间)。

  • [...]

内置

  • [...]

  • 已删除reduce()functools.reduce()如果确实需要,请使用它;但是,99% 的情况下,显式for循环更易读。

  • [...]

解决方案 2:

map和的功能filter被有意更改为返回迭代器,并且 reduce 被从内置函数中移除并放置在 中functools.reduce

因此,对于filtermap,您可以用它们包装起来list()以查看结果,就像之前所做的那样。

>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> list(filter(f, range(2, 25)))
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> list(map(cube, range(1, 11)))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>> import functools
>>> def add(x,y): return x+y
...
>>> functools.reduce(add, range(1, 11))
55
>>>

现在的建议是,用生成器表达式或列表推导式替换 map 和 filter 的使用。例如:

>>> def f(x): return x % 2 != 0 and x % 3 != 0
...
>>> [i for i in range(2, 25) if f(i)]
[5, 7, 11, 13, 17, 19, 23]
>>> def cube(x): return x*x*x
...
>>> [cube(i) for i in range(1, 11)]
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
>>>

他们说 for 循环 99% 的时间比 reduce 更容易阅读,但我还是坚持使用functools.reduce

编辑:99% 这个数字直接取自Guido van Rossum 撰写的“Python 3.0 的新功能”页面。

解决方案 3:

作为其他答案的补充,这听起来像是一个上下文管理器的很好用例,它将这些函数的名称重新映射到返回列表并reduce在全局命名空间中引入的名称。

快速实施可能如下所示:

from contextlib import contextmanager    

@contextmanager
def noiters(*funcs):
    if not funcs: 
        funcs = [map, filter, zip] # etc
    from functools import reduce
    globals()[reduce.__name__] = reduce
    for func in funcs:
        globals()[func.__name__] = lambda *ar, func = func, **kwar: list(func(*ar, **kwar))
    try:
        yield
    finally:
        del globals()[reduce.__name__]
        for func in funcs: globals()[func.__name__] = func

用法如下:

with noiters(map):
    from operator import add
    print(reduce(add, range(1, 20)))
    print(map(int, ['1', '2']))

打印内容:

190
[1, 2]

仅代表我个人观点 :-)

解决方案 4:

由于该reduce方法已从 Python3 的内置函数中移除,请不要忘记functools在代码中导入。请查看下面的代码片段。

import functools
my_list = [10,15,20,25,35]
sum_numbers = functools.reduce(lambda x ,y : x+y , my_list)
print(sum_numbers)

解决方案 5:

map、filter 和 reduce 的优点之一是,当你将它们“链接”在一起以执行复杂操作时,它们会变得非常清晰。但是,内置语法并不清晰,而且完全是“倒退的”。因此,我建议使用PyFunctional包 ( https://pypi.org/project/PyFunctional/ )。
以下是两者的比较:

flight_destinations_dict = {'NY': {'London', 'Rome'}, 'Berlin': {'NY'}}

PyFunctional 版本

语法非常清晰。你可以说:

“我有一系列航班目的地。如果城市在字典值中,我想从中获取字典键。最后,过滤掉我在此过程中创建的空列表。”

from functional import seq  # PyFunctional package to allow easier syntax

def find_return_flights_PYFUNCTIONAL_SYNTAX(city, flight_destinations_dict):
    return seq(flight_destinations_dict.items()) \n        .map(lambda x: x[0] if city in x[1] else []) \n        .filter(lambda x: x != []) \n

默认 Python 版本

这完全是倒退的。你需要说:

“好的,所以,有一个列表。我想从中过滤掉空列表。为什么?因为如果城市在字典值中,我首先会得到字典键。哦,我正在执行此操作的列表是 flight_destinations_dict。”

def find_return_flights_DEFAULT_SYNTAX(city, flight_destinations_dict):
    return list(
        filter(lambda x: x != [],
               map(lambda x: x[0] if city in x[1] else [], flight_destinations_dict.items())
               )
    )

解决方案 6:

from functools import reduce

def f(x):
    return x % 2 != 0 and x % 3 != 0

print(*filter(f, range(2, 25)))
#[5, 7, 11, 13, 17, 19, 23]

def cube(x):
    return x**3
print(*map(cube, range(1, 11)))
#[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

def add(x,y):
    return x+y

reduce(add, range(1, 11))
#55

它按原样工作。要获取 map 的输出,请使用 * 或 list

解决方案 7:

以下是 Filter、map 和 Reduce 函数的示例。

numbers = [10,11,12,22,34,43,54,34,67,87,88,98,99,87,44,66]

筛选:

oddNumbers = list(filter(lambda x: x%2 != 0, numbers))

print(oddNumbers)

地图:

multiplyOf2 = list(map(lambda x: x*2, numbers))

print(multiplyOf2)

由于 reduce 函数不常用,因此已从 Python 3 的内置函数中删除。但它仍然可以在 functools 模块中使用,因此您可以执行以下操作:

from functools import reduce

sumOfNumbers = reduce(lambda x,y: x+y, numbers)

print(sumOfNumbers)

解决方案 8:

functools.reduce对于深入研究嵌套键数据结构也很有用:

from functools import reduce
from operator import getitem

# ...

megayaml = defaultdict(lambda: {})

for datum in someInput:
    deepK = datum['Key'].split('/')
    value = b64decode(datum['Value'])
     
    start = megayaml[f"{some}-{complicated}-{toplevel}-{key}.irrelevant"]

    parents, leaf = deepK[:-1], deepK[-1]
    bottom = reduce(getitem, parents, start)
    bottom[leaf] = value

我导入的operator.getitem当然在道德上等同于lambda drill, step: drill[step]。结合collections.defaultdict,此代码片段允许我“展开”一棵树,并从表格转储中重建它。

是的,Guido,说“reduce 总是可以重写为 for 循环”很容易— 除非你已经有几个循环深度,而事实并非如此。Thenreduce(getitem, …)要简单得多。


至于映射和过滤结果的惰性,有一个简单的习语:

data = filter(…)
data = map(…, data)
data = list(data) # force lazy list
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用