【问题标题】:Accessing the list while being sorted在排序时访问列表
【发布时间】:2014-05-05 20:48:47
【问题描述】:

我可以在list.sort() 中对列表进行排序时访问它吗

b = ['b', 'e', 'f', 'd', 'c', 'g', 'a']
f = 'check this'

def m(i):
    print i, b, f
    return None

b.sort(key=m)
print b

返回

b [] check this
e [] check this
f [] check this
d [] check this
c [] check this
g [] check this
a [] check this

请注意,列表 b 的各个项目被发送到函数 m。但是在m 列表b 是空的,但是它可以看到变量f,它与列表b 具有相同的范围。为什么函数m 打印b[]

【问题讨论】:

  • m 确实可以看到列表b(否则会引发错误),只是一调用sort 就为空。
  • 没错,我现在改了问题。

标签: python list sorting python-internals


【解决方案1】:

看看source code(CPython,其他实现可能有不同的行为)你的脚本的奇怪输出变得很明显:

/* The list is temporarily made empty, so that mutations performed
 * by comparison functions can't affect the slice of memory we're
 * sorting (allowing mutations during sorting is a core-dump
 * factory, since ob_item may change).
 */
saved_ob_size = Py_SIZE(self);
saved_ob_item = self->ob_item;
saved_allocated = self->allocated;
Py_SET_SIZE(self, 0);

评论说明了一切:当您开始排序时,列表被清空。好吧,在外部观察者的眼中它是“空的”。

我很喜欢“核心转储工厂”这个词。


比较一下:

b = ['b','e','f','d','c','g','a']
f = 'check this'


def m(i):
    print i, b, f
    return None

b = sorted(b, key= m)
print b

【讨论】:

【解决方案2】:

这是您一般不能依赖的东西 - 不仅仅是列表 - 除非您正在使用的方法的文档明确另有说明。访问处于中间状态的对象 - 即,在一些迭代开始之后,但在它完成之前 - 是并发代码经常遇到的问题。您发现了一个罕见的非并发案例,但建议是相同的:避免这种情况。中间状态不保证对您有意义,也不保证根据该对象的规则是“有效”状态(当它往往被称为“不一致”状态时)。

【讨论】:

  • +1 来自我。可变性是所有编程的终结。 :-) State Monad FTW!
  • 如果我想通过调用使用项目索引作为参数的函数对列表进行排序怎么办。有没有办法做到这一点,而不复制原始列表?
  • @nr.o 就像在我的回答中发布的那样:您可以使用 sorted 代替(这也会创建一个副本,因此实际上没有真正的收益,但您不必明确复制它)。
  • @nr.o:如果你想使用索引,你将使用sorted(enumerate(l), key=whatever)而不是调用index,因为index在列表中慢得多并且容易出错包含重复项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 2019-04-07
  • 1970-01-01
  • 2023-02-21
  • 2015-07-11
相关资源
最近更新 更多