Python 列表调用 sort 后,接收结果的变量变成 None
Python list.sort 原地修改列表并返回 None,空列表也不例外。按是否需要修改输入选择单独调用 sort 或返回 sorted 新列表,核对别名、空输入与恢复原顺序的边界。
result = values.sort() 没有得到排好序的列表,而是得到 None。空列表也一样:[].sort() 的结果不是 []。随后对 result 取长度或遍历,便可能报与 NoneType 有关的错误。
Python 3 内置列表的 sort() 会直接修改原列表,成功时返回 None。因此要先确定需要修改输入,还是需要另一个有序列表,再改调用方式。这里不涉及第三方对象上同名方法的返回约定。
把修改后的列表与方法返回值分开看
下面的例子同时保留原对象和返回值,便于定位赋值发生在哪里:
values = [3, 1, 2]
alias = values
result = values.sort()
print(values) # 预期 [1, 2, 3]
print(result is None) # 预期 True
print(alias is values) # 预期 True
列表并没有因为返回 None 而被清空;values 和 alias 仍指向已经排序的同一个对象。若写成 values = values.sort(),赋值会让 values 改为指向 None,但其他引用仍可能持有原列表。
因此不要在后续补上 values or [] 来掩盖错误。对于原本非空的输入,这会把本应保留的数据误当成空结果。
需要修改输入时,单独调用 sort
调用方就是要原地排序,可以省去接收返回值:
values = [3, 1, 2]
values.sort()
print(values) # 预期 [1, 2, 3]
封装成函数并且约定返回这份列表时,应先排序,再返回对象:
def order_in_place(values):
values.sort()
return values
values = [3, 1, 2]
result = order_in_place(values)
print(result is values) # 预期 True
return values.sort() 则会把 None 返回给调用方。两行写法并非只影响返回值:函数仍会修改调用方传入的列表,其他持有它的代码也会看到顺序变化。
需要保留输入顺序时,改用 sorted
如果函数应返回新列表,用 sorted() 表达这个约定:
def ordered_copy(values):
return sorted(values)
values = [3, 1, 2]
result = ordered_copy(values)
print(values) # 预期 [3, 1, 2]
print(result) # 预期 [1, 2, 3]
print(result is values) # 预期 False
print(ordered_copy([])) # 预期 []
这时原列表的顺序不变,空输入得到一个空列表。原先带有 key= 或 reverse= 的排序,应把这些参数一并保留;修复返回值不能顺手改变排序规则。
sorted() 创建的是新的列表容器,不是把所有元素都深拷贝。元素若是可变对象,两个列表仍可能引用同一对象。这里承诺保留的是输入列表的排列,不是隔离元素内部状态。
验证空输入、返回类型和调用方副作用
分别用空列表、单个元素和乱序列表检查。原地版本应保持对象身份并改变必要的顺序;复制版本应返回新的列表并保留输入顺序。不要只检查打印出来的元素,还要确认调用方是否依赖原对象被修改。
如果 sort() 已经抛出了比较异常,例如元素之间不能比较,便不是成功返回 None 这条路径。异常不会被排序方法自动吞掉,失败时列表还可能已部分调整,不能把异常当成“空结果”继续处理。
撤回代码时,应恢复事先约定的原地或复制行为。排序本身不保留原来的排列;如果其他逻辑需要恢复原顺序,应在排序前保留列表副本,而不是排序之后再猜回去。已经执行了 values = values.sort() 时,也不能靠再次调用 sort() 从 None 找回原列表,需要使用仍保留的引用或原始数据重新构建。


