在 Python 3 对象列表中对所有对象调用方法的惯用方法

Nei*_*eil 6 python methods list python-3.x

我有一个对象列表,它们有一个名为 process 的方法。在 Python 2 中可以做到这一点

map(lambda x: x.process, my_object_list)
Run Code Online (Sandbox Code Playgroud)

在 Python 3 中,这将不起作用,因为 map 在遍历迭代之前不会调用该函数。可以这样做:

list(map(lambda x: x.process(), my_object_list))
Run Code Online (Sandbox Code Playgroud)

但是你会用一次性列表浪费内存(如果列表很大,这是一个问题)。我也可以使用 2 行显式循环。但是这种模式对我来说太常见了,我不想或认为我应该每次都写一个循环。

在 Python 3 中是否有更惯用的方法来做到这一点?

che*_*ner 7

不要map在简单for循环中使用或列表理解:

for x in list_of_objs:
    x.process()
Run Code Online (Sandbox Code Playgroud)

它并不比您可能用来抽象它的任何函数长得多,但它要清晰得多。

当然,如果process返回一个有用的值,那么一定要使用列表推导式。

results = [x.process() for x in list_of_objs]
Run Code Online (Sandbox Code Playgroud)

map

results = list(map(lambda x: x.process(), list_of_objs))
Run Code Online (Sandbox Code Playgroud)

有一个可用的函数可以map减少笨拙,特别是如果您要重用调用者:

from operator import methodcaller
processor = methodcaller('process')
results = list(map(processor, list_of_objs))
more_results = list(map(processor, another_list_of_objs))
Run Code Online (Sandbox Code Playgroud)

如果你正在为一个函数寻找一个好名字来包装循环,Haskell 有一个很好的约定:以下划线结尾的函数名丢弃它的“返回值”。(实际上,它丢弃了 monadic 操作的结果,但为了这个答案的目的,我宁愿忽略这种区别。)

def map_(f, *args):
    for f_args in zip(*args):
        f(*f_args)

# Compare:
map(f, [1,2,3])  # -- return value of [f(1), f(2), f(3)] is ignored
map_(f, [1,2,3])  # list of return values is never built
Run Code Online (Sandbox Code Playgroud)

  • 如果不需要迭代器,为什么要使用`map` 来构建迭代器?循环是在对象列表上立即调用函数的惯用的 Pythonic 方法。 (3认同)
  • 函数式编程更多地是在数学意义上使用函数,而不仅仅是优先于其他句法结构调用函数。Python 中被认为是“函数式”的大部分内容实际上是面向流的编程。 (2认同)

sch*_*tte 5

既然您正在寻找 Pythonic 解决方案,为什么还要费力尝试适应map(lambda x: x.process, my_object_list)Python 3 呢?

一个简单的 for 循环还不够吗?

for x in my_object_list:
    x.process()
Run Code Online (Sandbox Code Playgroud)

我的意思是,这是简洁可读的,并且如果不需要返回值,可以避免创建不必要的列表。