Python中是否有类似于'map'的原地操作等价物?

16

我有一个字符串列表需要进行清理。我已经有了一个用于清理的方法,所以我可以这样做:

new_list = map(Sanitize, old_list)

但我不需要保留旧列表。这让我想知道是否有一个类似于map的原地等效函数。编写循环或自定义的原地map方法都很容易,但是否有内置的方法呢?


1
是的,这是一个重复的问题。 我发誓我搜索过了,看看是否已经有人问过了。显然我的搜索技巧还不够好。 :) - Herms
4
这并不是一个有意义的重复问题,因为那个问题没有得到回答。旧问题通常不会被回答(没有办法“顶”问题),因此关闭它们并不合理。这样关闭重复问题实际上会使它们无法得到回答。 - Glenn Maynard
2
@aaronasterling:不,#3000461中没有这个问题的答案。这个问题被错误地关闭了。 - Glenn Maynard
1
这仍然会创建一个新列表,但是重用旧列表的引用old_list[:] = map(Sanitize, old_list) - John La Rooy
@gnibbler:实际上并不是原地操作,但由于OP的真正目标(根据下面的评论判断)似乎是“将结果放在调用者给出的同一列表中”,并且并不太关心它是否真正地原地操作,所以这可能是可以接受的。然而,我有一些直觉上的犹豫;我可能仍然会编写一个真正的原地操作函数。 - Glenn Maynard
显示剩余3条评论
4个回答

13
简单回答:没有。
当答案是否定的时候,形如“XXX是否存在”的问题通常不会得到直接回答。这就是为什么我想把它说出来。
大多数itertools帮助程序和内置函数都适用于通用的迭代器。map、filter、列表推导式以及for循环——它们都适用于迭代器,而不修改原始容器(如果有的话)。
为什么在这个类别中没有任何可变函数呢?因为没有一种通用的、普遍适用于容器键值对赋值的方式。例如,基本的字典迭代器(for x in {})迭代键,并使用字典的结果作为[]的参数进行赋值。另一方面,列表迭代器迭代值,并使用隐含的索引进行赋值。缺乏底层一致性,无法提供这样的通用函数,因此在itertools或内置函数中没有类似的函数。
他们可以将其提供为list和dict的方法,但目前还没有。你只需要自己编写。

3
简单的网络搜索表明,"XXX"确实存在,尽管它通常不属于Stack Overflow的讨论范围。 - Jean-François Corbett
1
@Jean-FrançoisCorbett在评论区变得火热而激烈。 - sam-pyt

6

你需要循环:

for i in range(len(old_list)):
    old_list[i] = Sanitize(old_list[i])

没有内置的功能。

如评论中建议的:按照OP所需的函数:

def map_in_place(fn, l):
    for i in range(len(l)):
        l[i] = fn(l[i])

map_in_place(Sanitize, old_list)

在你的for循环之前加上def map_in_place(func, a_list):,我们就有了一个完整的答案。(但是old_list = map(Sanitize, old_list)虽然不会改变旧列表,但似乎是最好的解决方案。) - Steven Rumbalski

5
与使用this[0] = something类似,您也可以指定切片:

>>> x = [1, 2, 3, 4]
>>> x[1:3] = [0, 0]
>>> x
[1, 0, 0, 4]

由于切片可以省略某些部分(起始、终止或步长),您可以通过以下方式更改整个列表:

>>> x = [1, 2, 3, 4]
>>> x[:] = [4, 5, 6]
>>> x
[4, 5, 6]

这个示例(如上所示)可以更改列表的长度。正如下面所看到的,这确实改变了实际对象,而不是重新定义变量:
>>> x = [1, 2, 3, 4]
>>> y = x
>>> x[:] = [3, 4]
>>> y
[3, 4]

在赋值语句的右侧,不一定需要是一个列表。任何可迭代的对象都可以出现在那一侧。事实上,你甚至可以使用一个生成器:

>>> x = ["1", "2", "3", "4"]
>>> x[:] = (int(y) for y in x)
>>> x
[1, 2, 3, 4]
< p > 或者< code >map() 的返回值(在 Python 2 中为列表;在 Python 3 中为< code >map 对象):

>>> x = ["1", "2", "3", "4"]
>>> x[:] = map(int, x)

2

说到底,

old_list = map(Sanitize, old_list)

将会完全按照您的需求完成。

您可能会认为创建一个新的列表对象并回收旧的对象比使用现有对象要慢。实际上,这几乎永远不会成为问题(分配一块内存作为一次性操作不太可能成为瓶颈;如果您正在循环中执行此操作或者有一个非常长的列表,可以尝试进行基准测试,但我仍然会反对)。请记住,无论哪种方式,您都必须从头开始创建新字符串作为Sanitize的一部分,这将会更加昂贵。

值得注意的是,正如mluebke所指出的那样,这些天列表推导式被认为比map更具有"Python风格"(我相信map在未来的版本中已被弃用)。

编辑:啊,我看到您正在尝试编辑传递给函数的参数值。我强烈主张这是"不符合Python风格"的,您应该将新列表作为返回值之一返回(请记住,使用元组您可以拥有多个返回值)。


原地位并不是垃圾回收问题。问题在于我正在将这个清理过程插入到一些不返回结果的代码中。它只是改变当前列表(列表中还有很多其他东西也被修改)。所以我需要改变它。 - Herms

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接