【问题标题】:Idiomatic way to call method on all objects in a list of objects Python 3在对象列表中的所有对象上调用方法的惯用方式 Python 3
【发布时间】:2019-01-02 07:40:57
【问题描述】:

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

map(lambda x: x.process, my_object_list)

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

list(map(lambda x: x.process(), my_object_list))

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

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

【问题讨论】:

  • 仅供参考,您并不真的需要 lambda。假设x 的类型是X,那么map(X.process, list_of_objects) 可以正常工作
  • @DeepSpace 做假设通常是不好的,而支持多态性通常是好的(:
  • 如果你不想每次都写两行代码,把这两行代码塞进一个函数里。这就是函数的用途。
  • "In Python 3... map doesn't call the function until the iterable is traversed." 后跟:"But then you waste memory with a throwaway list..." 只是想确保您确实了解在 Python 2 中,被丢弃的 list 仍然是这种情况。在 3 中切换到迭代器是一个很大的改进。无论如何:只需使用 for 循环。没有优越的成语。

标签: python python-3.x list methods


【解决方案1】:

不要使用map 或简单的for 循环可以使用的列表解析:

for x in list_of_objs:
    x.process()

它并不比你可能用来抽象它的任何函数长得多,但它明显更清晰。

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

results = [x.process() for x in list_of_objs]

map:

results = list(map(lambda x: x.process(), list_of_objs))

有一个可用的函数可以让map 不那么笨重,特别是如果您要重用调用者:

from operator import methodcaller
processor = methodcaller('process')
results = list(map(processor, list_of_objs))
more_results = list(map(processor, another_list_of_objs))

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

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

【讨论】:

  • 我不确定,但我认为这错过了 OPs 问题背后的想法。很明显,他们只想使用 map 返回的生成器,而不需要:1. 通过列表解析或 list(map(...))2. 创建列表编写一个“显式”循环
  • 如果您不想要迭代器,为什么要使用map 来构建迭代器?循环是在对象列表上立即调用函数的惯用 Pythonic 方法。
  • 有趣的是,您使用 Haskell 作为灵感。回想起来,我认为我遇到困难的概念原因是因为 map 非常“实用”,我试图让它与一个类的对象一起玩得很好。无论如何,一些人评论说,抽象这种模式的适当方法是将其包装在一个函数中。我的问题要求一种避免每次都编写循环的方法,虽然大多数人建议必须明确编写循环,但这个答案提供了一些更实用的指导,将这种行为包装在一个函数中,所以我接受它。
  • 函数式编程更多的是在数学意义上使用函数,而不仅仅是调用函数而不是其他语法结构。 Python 中被认为是“函数式”的大部分内容实际上是面向流的编程。
【解决方案2】:

既然您正在寻找 Python 风格的解决方案,为什么还要费心尝试将 map(lambda x: x.process, my_object_list) 用于 Python 3?

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

for x in my_object_list:
    x.process()

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-24
    相关资源
    最近更新 更多