【问题标题】:Python LIST functions not returning new listsPython LIST 函数不返回新列表
【发布时间】:2012-04-02 20:20:10
【问题描述】:

我在考虑内置 Python 列表方法时遇到问题。

在我学习 Python 的过程中,我一直认为 Python mutator 就像任何值类 mutator 都应该做的那样,返回它创建的新变量。

举个例子:

a = range(5)
# will give [0, 1, 2, 3, 4]
b = a.remove(1)
# as I learned it, b should now be [0, 2, 3, 4]
# what actually happens:
# a = [0, 2, 3, 4]
# b = None

这个列表修改器没有返回一个新列表的主要问题是你不能在随后进行多个突变。 假设我想要一个从 0 到 5 的列表,没有 2 和 3。 返回新变量的变异器应该能够这样做:

a = range(5).remove(2).remove(3)

很遗憾,这是不可能的,就像range(5).remove(2) = None

现在,有没有办法像我在我的示例中那样对列表进行实际执行多个突变?我认为即使是 PHP 也允许使用字符串进行这些类型的后续突变。

我也找不到关于所有内置 Python 函数的好的参考资料。如果有人能找到所有列表修改器方法的实际定义(带有返回值),请告诉我。我只能找到这个页面:http://docs.python.org/tutorial/datastructures.html

【问题讨论】:

  • “当我学习 Python 时,我一直认为 Python mutators 就像任何值类 mutators 应该做的那样,返回它创建的新变量。” ——你从哪里学来的?事实上,在 Python 中拥有具有可变状态的对象是很常见的,列表就是其中之一。 (字符串不是。)

标签: python list


【解决方案1】:

而不是同时改变和返回对象,Python 库选择只有一种方式来使用改变器的结果。来自import this

应该有一种——最好只有一种——明显的方法。

话虽如此,更常用的 Python 风格是使用 list comprehensionsgenerator expressions

[x for x in range(5) if x != 2 and x != 3]

您也可以将这些链接在一起:

>>> [x for x in (x for x in range(5) if x != 2) if x != 3]
[0, 1, 4]

上面的生成器表达式还有一个额外的优势,它可以在 O(n) 时间内运行,因为 Python 只迭代 range() 一次。对于大型生成器表达式,甚至对于 infinite 生成器表达式,这是有利的。

【讨论】:

  • 嗯,我想在使用列表排除时,这样做会很方便:[ x for x in range(5) if not x in (2, 3) ]
【解决方案2】:

在 Python 中,基本上所有改变对象的方法都返回 None

这样你就不会意外地认为你得到了一个新对象。

你提到

我认为即使是 PHP 也允许使用字符串进行这些类型的后续突变。

虽然我不记得 PHP,但使用字符串操作,您可以链接方法调用,因为 字符串是不可变的,所以 所有字符串方法都返回一个新字符串,因为它们不会(不能)更改您调用它们的字符串。

>>> "a{0}b".format(3).center(5).capitalize().join('ABC').swapcase()
'a A3B b A3B c'

【讨论】:

    【解决方案3】:

    list 和其他可变类型的许多方法有意返回 None,这样您就不会怀疑您是在创建新对象还是更改现有对象。唯一可能发生的事情是突变,因为如果创建了一个新对象,它必须由方法返回,并且不会返回。

    您可能已经注意到,str 编辑字符串的方法确实返回了新字符串,因为字符串是不可变的,并且总是返回一个新字符串。

    当然,没有什么能阻止你编写一个在.append() 上具有所需行为的list 子类等, 尽管这似乎是一个沉重的锤子,仅用于允许您链接方法调用。此外,大多数 Python 程序员不会期望这种行为,从而使您的代码不太清晰。

    【讨论】:

      【解决方案4】:

      Python 或 php 都没有内置的“mutators”。你可以简单地写多行,比如

      a = list(range(5))
      a.remove(2)
      a.remove(3)
      

      如果要生成新列表,请事先复制旧列表:

      a = list(range(5))
      b = a[:]
      b.remove(2)
      

      请注意,在大多数情况下,对remove 的单数调用表明您应该首先使用set

      【讨论】:

      • 只有在 Python 3 上才需要调用 list
      • setlist 的使用有何不同?
      • @stevenroose 如果你想通过它的值删除一个特定的元素,set 将具有 O(log n),甚至 O(1) 的性能。一般来说,list的性能会在O(n)左右。
      • Python 集在后台使用哈希表,即O(1)
      【解决方案5】:

      要删除列表上的多个突变,就像你想在你的例子中做的那样,你可以这样做:

      a = range(5)
      a = [i for j, i in enumerate(a) if j not in [2, 3]]
      

      a 将是 [0, 1, 4]

      【讨论】:

      • 备注:list.remove(x) 方法会删除值为 x 的项目,而不是您的脚本所做的索引 x 处的项目。对于做同样事情的range() 列表,对于其他列表,它可能不会做正确的事情;)
      猜你喜欢
      • 1970-01-01
      • 2017-07-22
      • 2021-10-07
      • 1970-01-01
      • 2013-10-22
      • 1970-01-01
      • 1970-01-01
      • 2014-03-17
      • 2013-11-13
      相关资源
      最近更新 更多