【问题标题】:Why does '.sort()' cause the list to be 'None' in Python? [duplicate]为什么 '.sort()' 导致列表在 Python 中为 'None'? [复制]
【发布时间】:2012-04-04 08:22:10
【问题描述】:

我正在尝试对 ints 的 Python 列表进行排序,然后使用 .pop() 函数返回最高的列表。我尝试过以不同的方式编写方法:

def LongestPath(T):    
    paths = [Ancestors(T,x) for x in OrdLeaves(T)]
    #^ Creating a lists of lists of ints, this part works
    result =[len(y) for y in paths ]
    #^ Creating a list of ints where each int is a length of the a list in paths
    result = result.sort()
    #^meant to sort the result
    return result.pop()
    #^meant to return the largest int in the list (the last one)

我也试过了

def LongestPath(T):
    return[len(y) for y in [Ancestors(T,x) for x in OrdLeaves(T)] ].sort().pop()

在这两种情况下.sort() 导致列表为None(它没有.pop() 函数并返回错误)。当我删除 .sort() 时,它可以正常工作,但不会返回最大的 int,因为列表未排序。

【问题讨论】:

  • 有什么理由不使用max()
  • hc_,当我这样做时,我会收到 AttributeError: 'list' object has no attribute 'max'
  • 那是因为max() 是一个函数,而不是list 方法。
  • 来自 Python documentation:“您可能已经注意到,仅修改列表的插入、删除或排序等方法没有打印返回值——它们返回默认值 None。这是Python 中的所有可变数据结构。”

标签: python list sorting


【解决方案1】:

简单地删除分配

result = result.sort()

离开

result.sort()

sort 方法就地工作(它修改现有列表),因此不需要赋值,它返回None。当您将其结果分配给列表名称时,您分配的是None

它可以很容易(并且更有效地)写成单行:

max(len(Ancestors(T,x)) for x in OrdLeaves(T))

max 以线性时间 O(n) 运行,而排序时间为 O(nlogn)。您也不需要嵌套列表推导,一个生成器表达式就可以了。

【讨论】:

  • 好的,那么为什么第二种方法不起作用呢?为什么用 .sort() 返回列表会导致它返回 None
  • @Btuman 因为当您尝试.pop() 时,您仍在访问.sort() 的返回值——所以您尝试在两者中都执行None.pop(),而不是sortedlist.pop()版本。如果您真的想要使用单行和排序而不是max,您应该使用sorted(len(Ancestors(T,x)) for x in OrdLeaves(T))[-1].pop() 做了两件事——它删除并返回最后一个值。既然只需要退回,不用删除,就用[-1]吧。
  • @Btuman 需要明确的是,.sort() 不会“导致列表为None”,它只是返回None。但是,当您将 None 分配给名称 result 时,您将无法访问排序列表——result 不再指向它。同一行中也发生了同样的事情——当您执行.sort() 时,您将无法访问列表,因为您只能访问内部表达式的结果,而.sort() 的结果是None不是它修改的列表。
【解决方案2】:

这个

result = result.sort()

应该是这样的

result.sort()

在 Python 中,改变序列的方法返回 None 是一种约定。

考虑:

>>> a_list = [3, 2, 1]
>>> print a_list.sort()
None
>>> a_list
[1, 2, 3]

>>> a_dict = {}
>>> print a_dict.__setitem__('a', 1)
None
>>> a_dict
{'a': 1}

>>> a_set = set()
>>> print a_set.add(1)
None
>>> a_set
set([1])

此设计决策背后的 Python 设计和历史常见问题解答 gives the reasoning(关于列表):

为什么list.sort() 不返回排序后的列表?

在性能很重要的情况下,制作列表的副本 只是为了排序会很浪费。因此,list.sort() 对 清单到位。为了提醒你这个事实,它不会返回 排序的列表。这样你就不会不小心上当了 当您需要排序副本但还需要保留时覆盖列表 周围未排序的版本。

在 Python 2.4 中添加了一个新的内置函数 - sorted()。 此函数从提供的迭代创建一个新列表,对其进行排序 并返回它。

【讨论】:

    【解决方案3】:

    .sort() 返回 None 并对列表进行就地排序。

    【讨论】:

      【解决方案4】:

      这已被正确回答:list.sort() 返回None。原因是“命令-查询分离”:

      http://en.wikipedia.org/wiki/Command-query_separation

      Python 返回None,因为每个函数都必须返回一些东西,并且约定是不产生任何有用值的函数应该返回None

      我以前从未见过您在它引用的行之后放置注释的约定,而是以克拉开头的注释指向该行。请将 cmets 放在它们引用的行之前。

      虽然您可以使用.pop() 方法,但您也可以只为列表编制索引。列表中的最后一个值始终可以使用-1 进行索引,因为在 Python 中,负索引“环绕”并从末尾向后索引。

      但我们可以进一步简化。您对列表进行排序的唯一原因是您可以找到它的最大值。为此,Python 中有一个内置函数:max()

      使用list.sort() 需要构建一个完整的列表。然后,您将从列表中提取一个值并将其丢弃。 max() 将消耗一个迭代器,而无需分配大量内存来存储列表。

      此外,在 Python 中,社区更喜欢使用称为 PEP 8 的编码标准。在 PEP 8 中,您应该使用小写来表示函数名称,并使用下划线来分隔单词,而不是 CamelCase。

      http://www.python.org/dev/peps/pep-0008/

      考虑到上述 cmets,这是我对您的函数的重写:

      def longest_path(T):
          paths = [Ancestors(T,x) for x in OrdLeaves(T)]
          return max(len(path) for path in paths)
      

      在对max() 的调用中,我们有一个“生成器表达式”,它计算列表paths 中每个值的长度。 max() 会从中提取值,保持最大,直到所有值都用完。

      但现在很明显,我们甚至不需要paths 列表。这是最终版本:

      def longest_path(T):
          return max(len(Ancestors(T, x)) for x in OrdLeaves(T))
      

      我实际上认为带有显式 paths 变量的版本更具可读性,但这并不可怕,如果可能有大量路径,您可能会注意到由于不构建和销毁paths 列表。

      【讨论】:

        【解决方案5】:

        list.sort() 不返回列表 - 它会破坏性地修改您正在排序的列表:

        In [177]: range(10)
        Out[177]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        
        In [178]: range(10).sort()
        
        In [179]:
        

        也就是说,max 会在列表中找到最大的元素,并且会比您的方法更有效。

        【讨论】:

          【解决方案6】:

          在 Python 中,sort() 是一个就地操作。所以result.sort() 返回None,但更改result 以进行排序。所以为了避免你的问题,当你调用sort()时不要覆盖result

          【讨论】:

            【解决方案7】:

            有什么理由不使用sorted 函数吗? sort() 仅在列表上定义,但 sorted() 可与任何可迭代对象一起使用,并按您期望的方式运行。排序详情见this article

            另外,因为它内部使用timsort,所以如果你需要先按key 1排序,然后按key 2排序,效率会很高。

            【讨论】:

              【解决方案8】:

              你想要实现的东西不需要自定义函数,你首先需要了解你正在使用的方法!

              sort()在python中创建一个列表就位,也就是说,从sort()返回的是None。列表本身已修改返回一个新列表。

              >>>results = ['list','of','items']
              >>>results
              
              ['list','of','items']
              
              >>>results.sort()
              >>>type(results)
              
              <type 'list'>
              
              >>>results
              
              ['items','list','of']
              
              >>>results = results.sort()
              >>>results
              >>>
              >>>type(results)
              
              <type 'NoneType'>
              

              如您所见,当您尝试分配 sort() 时,您不再拥有列表类型。

              【讨论】:

                猜你喜欢
                • 2013-08-14
                • 2015-08-30
                • 2022-07-21
                • 2019-11-14
                • 2020-09-11
                相关资源
                最近更新 更多