为什么 "return list.sort()" 返回的是 None,而不是列表本身?

289
我已经确认了findUniqueWords确实会产生一个排序的list。然而,它并不返回这个列表。为什么呢?
def findUniqueWords(theList):
    newList = []
    words = []

    # Read a line at a time
    for item in theList:

        # Remove any punctuation from the line
        cleaned = cleanUp(item)

        # Split the line into separate words
        words = cleaned.split()

        # Evaluate each word
        for word in words:

            # Count each unique word
            if word not in newList:
                newList.append(word)

    answer = newList.sort()
    return answer

3
这只是一个愚蠢的想法,但如果你想要一个独特项目的清单,为什么不转换成集合?然后,如果需要,您可以将它们转换回列表。theSet = set(theList)完成后,您只需要将其转换回列表:theList = list(theSet)完成。简单吧。 - runlevel0
1
补充一下@runlevel0所说的(这是个好主意):你可以使用sorted(theSet)theSet转换成一个排序后的列表。 - Zaz
1
@StephenBoesch:这不仅是为了防止链接(虽然这是其中的一部分),还为了避免对方法返回一个带有变更的新副本,还是直接变异所产生的混淆(如果 list.sort 返回一个 list,那么它是原始的 list 在原地变异,还是生成了一个新的?)。Python 内置对象坚持一个或另一个;对于像 str 这样的不可变类型的方法 确实 进行链接(它们不能在原地进行变异,因此会返回一个带有变异的新对象),而大多数可变类型的 list 方法则不会。但对于常见的情况,例如此类情况,存在 sorted 能够达到类似的效果。 - ShadowRanger
2
仅仅因为链式调用是一种语言中常见的API习惯,并不意味着它必须在每种语言中都存在,而且这与函数式编程几乎没有任何关系(函数式编程鼓励使用不可变值,这使得有关修改方法返回对象引用的问题无关紧要)。 - chepner
显示剩余5条评论
8个回答

358

list.sort 对列表进行原地排序,即它不会返回一个新的列表。只需编写:

newList.sort()
return newList

44
“return sorted(newList)”更短。虽然变量是局部的,但原地排序可能会改变某些情况下共享的变量。 - Jean-François Fabre
我还想补充一点,也许值得看一下这个:http://www.grantjenks.com/docs/sortedcontainers/,https://github.com/grantjenks/python-sortedcontainers。在我的情况下,我已经考虑从列表重构为集合,因为我不想要重复项,然后寻找一个SortedSet实现,在collections模块中没有找到...来源:https://dev59.com/b2025IYBdhLWcg3whWdm - JGFMK
11
为什么 sort 函数被设计成这样?如果返回已排序的列表而不是 None,是否会有性能开销或其他缺点? - Lei Yang
2
我也遇到了以下问题:print(newList.sort()) 输出了 None。但是当我执行 newList.sort() 然后再 print(newList) 就可以正常工作了。 - Kots
3
@LeiYang:小考一下,如果我执行b = a.sort(),然后执行b.pop(),对a的影响是什么?在某些语言中,.sort返回已排序的 a 的副本,而在其他语言中,则会原地排序并返回对a的引用。 Python通过使就地突变返回None而不是别名来消除歧义,因此混淆较少。如果需要复制(并且它适用于所有可迭代对象,而不只是列表),则使用sorted函数。大致上没有性能开销来让alist.sort()返回alist,只有不确定性。 - ShadowRanger
显示剩余2条评论

230
问题在这里:

answer = newList.sort()
< p >< code > sort < /code > 方法不会返回已排序的列表;相反,它会直接在原列表上进行排序。< /p > < p > 使用:< /p >
answer = sorted(newList)

18
大多数人需要知道的是:list.sort()sorted(list)之间的区别。 - geekoverdose
请参考此文档以获取更多详细信息 - https://realpython.com/python-sort/ - mental_matrix

69

这封来自Python开发者邮件列表的邮件是Guido van Rossum解释为什么他选择不在影响对象但不返回新对象的操作中返回self

这种编码风格源于其他语言中的一种流行方式(我相信特别是Lisp非常喜欢这种方式),可以像这样链接单个对象上的一系列副作用:

 x.compress().chop(y).sort(z)

这与

  x.compress()
  x.chop(y)
  x.sort(z)

我认为链式调用会影响可读性;这需要读者对每个方法都非常熟悉。第二种形式明确表明了每个调用都作用于同一个对象,即使你不太了解类和其方法,你也能理解第二个和第三个调用是应用在x上的(并且所有调用都是为了它们的副作用),而不是其他东西。

我希望保留链式调用来执行返回新值的操作,例如字符串处理操作:

 y = x.rstrip("\n").split(":").lower()

45
有趣的是,split(":").lower() 是一个错误的链式操作,因为 split 返回的是一个列表,该列表没有 lower 方法。 - SuperBiasedMan

31

Python有两种排序方式:一种是排序方法(或“成员函数”),另一种是排序函数。排序方法是作用于被命名对象的内容上-可以将其视为对象正在采取的重新排序的操作。排序函数是对由对象表示的数据的一个操作,并返回一个按排序顺序排列的具有相同内容的新对象。

给定一个名为l的整数列表,如果我们调用l.sort(),列表本身将被重新排序:

>>> l = [1, 5, 2341, 467, 213, 123]
>>> l.sort()
>>> l
[1, 5, 123, 213, 467, 2341]

这个方法没有返回值。但是如果我们尝试赋值 l.sort() 的结果呢?

>>> l = [1, 5, 2341, 467, 213, 123]
>>> r = l.sort()
>>> print(r)
None

r现在实际上等于空。这是程序员在离开Python一段时间后容易忘记的奇怪而有点烦人的细节之一(这也是我写这篇文章的原因,以便我不再忘记)。

另一方面,sorted()函数不会改变l的内容,但会返回一个新的已排序列表,其内容与l相同:

>>> l = [1, 5, 2341, 467, 213, 123]
>>> r = sorted(l)
>>> l
[1, 5, 2341, 467, 213, 123]
>>> r
[1, 5, 123, 213, 467, 2341]

需要注意的是,返回的值并不是深度拷贝,因此对列表中包含的元素进行副作用操作时要像通常一样小心:

>>> spam = [8, 2, 4, 7]
>>> eggs = [3, 1, 4, 5]
>>> l = [spam, eggs]
>>> r = sorted(l)
>>> l
[[8, 2, 4, 7], [3, 1, 4, 5]]
>>> r
[[3, 1, 4, 5], [8, 2, 4, 7]]
>>> spam.sort()
>>> eggs.sort()
>>> l
[[2, 4, 7, 8], [1, 3, 4, 5]]
>>> r
[[1, 3, 4, 5], [2, 4, 7, 8]]

2
lst.sort()sorted(lst) 的区别是有帮助的。 - Marc Compere

17

Python通常从突变数据的函数和方法(例如list.sortlist.appendrandom.shuffle)中返回None,这表明它提示了它是在进行突变操作。

如果您想要获取可迭代对象并返回其项目的新排序列表,请使用内置函数sorted


9
为了弄清为什么它无法返回列表:
sort()不返回任何值,而sort()方法只是按照特定的顺序(升序或降序)对给定列表中的元素进行排序,但不返回任何值。
所以问题出在answer = newList.sort(),其中答案为none。
相反,你可以直接使用return newList.sort()
sort()方法的语法如下:
list.sort(key=..., reverse=...)

另外,您也可以使用Python内置的sorted()函数来完成相同的目的。

sorted(list, key=..., reverse=...)

注意:sort() 和 sorted() 最简单的区别是:sort() 不返回任何值,而 sorted() 返回可迭代的列表。
因此,在您的情况下,answer = sorted(newList)

2
相反,你可以直接返回 newList.sort()......,这是具有误导性的。它将返回 None 而不是已排序的列表。所以,是的,你可以这样做,但可能不会达到预期的效果。 - pjm

8

以下是一条我在其他回答中没有看到的小贴士:

Python 中所有修改可变对象(例如列表)的方法都会返回 None。因此,对于列表来说,这也包括 list.append(), list.reverse()等等。这就是为什么语法应该是:

myList.sort()

与此同时,对于任何不可变对象(例如字符串)的方法必须像下面这样被赋值:

myString = myString.strip()


正是我的问题。如果你正在使用lambda,请使用sorted代替。 - Alexander Santos

4
如果你想要返回排序后的列表,可以使用sorted()方法。这样更加方便。
l1 = []
n = int(input())

for i in range(n):
  user = int(input())
  l1.append(user)
sorted(l1,reverse=True)

list.sort()方法会就地修改列表,并返回None。

如果您仍然想使用sort方法,可以这样做。

l1 = []
n = int(input())

for i in range(n):
  user = int(input())
  l1.append(user)
l1.sort(reverse=True)
print(l1)

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