【问题标题】:Why does `mylist[:] = reversed(mylist)` work?为什么 `mylist[:] = reversed(mylist)` 有效?
【发布时间】:2015-08-16 17:17:36
【问题描述】:

以下内容“就地”反转列表并在 Python 2 和 3 中工作:

>>> mylist = [1, 2, 3, 4, 5]
>>> mylist[:] = reversed(mylist)
>>> mylist
[5, 4, 3, 2, 1]

为什么/如何?由于reversed 给了我一个迭代器并且没有事先复制列表,并且由于[:]= 替换了“就地”,我很惊讶。以下同样使用reversed,按预期中断:

>>> mylist = [1, 2, 3, 4, 5]
>>> for i, item in enumerate(reversed(mylist)):
        mylist[i] = item
>>> mylist
[5, 4, 3, 4, 5]

为什么[:] = 不会那样失败?

是的,我知道mylist.reverse()

【问题讨论】:

  • l[a:b] = l 还有一个特殊情况。
  • @user2357112 哇哦,太酷了。不确定我是否曾经使用过它,但我可能会下意识地害怕甚至无法想到它:-)
  • 第一个 sn-p not 执行就地算法(如 O(1) 或恒定空间复杂度),所以是时候开始质疑说的来源了它是。 en.wikipedia.org/wiki/In-place_algorithm
  • 请注意 wiki 文章中的一句话:一种算法有时会非正式地被就地调用,只要它的输出覆盖其输入即可。 i> 但是正式的定义也需要恒定的空间复杂度。因此,混淆可能是由于对短语真正含义背后的误解造成的。
  • @Shashank 好吧,我确实将“就地”放在引号中:-P。此外,如果右侧是一个列表,我认为它实际上会在严格的复杂性意义上就位(seems to just copy the elements)。但实际上我有一个更宽松的定义,不是那种算法复杂性,而是数据写入旧对象而不是新对象的意义上。例如,list.sort() 被记录为 “对列表中的项目进行排序。” 我不认为它们意味着 O(1) 额外的空间。

标签: python list reverse assign python-internals


【解决方案1】:

CPython 列表切片分配将首先通过调用PySequence_Fast 将可迭代对象转换为列表。来源:https://hg.python.org/cpython/file/7556df35b913/Objects/listobject.c#l611

 v_as_SF = PySequence_Fast(v, "can only assign an iterable");

即使是 PyPy 也会做一些事情 similar:

def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_iterable):
    length = w_list.length()
    start, stop = normalize_simple_slice(space, length, w_start, w_stop)
    sequence_w = space.listview(w_iterable)
    w_other = W_ListObject(space, sequence_w)
    w_list.setslice(start, 1, stop-start, w_other)

这里space.listview 将调用ObjSpace.unpackiterable 来解压迭代器,而迭代器又返回一个列表。

【讨论】:

  • 太好了,感谢这两个链接。我有时会自己挖掘源代码,尽管在 C 部分有点迷失。很高兴看到 user2357112 提到的 a[i:j] = a 特殊情况在那里得到了处理。
猜你喜欢
  • 2020-05-17
  • 2019-05-03
  • 2023-02-24
  • 2012-08-18
  • 1970-01-01
  • 2011-12-11
  • 2011-08-11
  • 2017-02-19
  • 2018-02-19
相关资源
最近更新 更多