按可以为 None 的属性对列表进行排序

新手上路,请多包涵

我正在尝试使用对对象列表进行排序

my_list.sort(key=operator.attrgetter(attr_name))

但如果任何列表项有 attr = None 而不是 attr = 'whatever'

然后我得到一个 TypeError: unorderable types: NoneType() < str()

在 Py2 中这不是问题。我如何在 Py3 中处理这个问题?

原文由 AlexVhr 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 709
2 个回答

排序比较运算符对 Python 3 中 类型更加严格,如下所述:

当操作数没有有意义的自然排序时,排序比较运算符(<、<=、>=、>)会引发 TypeError 异常。

Python 2 排序 None 在任何字符串(甚至是空字符串)之前:

 >>> None < None
False

>>> None < "abc"
True

>>> None < ""
True

在 Python 3 中,任何排序 NoneType 实例的尝试都会导致异常:

 >>> None < "abc"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: NoneType() < str()

我能想到的最快解决方法是将 None 实例显式映射到可订购的对象中,例如 ""

 my_list_sortable = [(x or "") for x in my_list]

如果您想在保持数据完整的同时对数据进行排序,只需提供 sort 一个自定义的 key 方法:

 def nonesorter(a):
    if not a:
        return ""
    return a

my_list.sort(key=nonesorter)

原文由 jsalonen 发布,翻译遵循 CC BY-SA 3.0 许可协议

对于通用解决方案,您可以定义一个比较小于任何其他对象的对象:

 from functools import total_ordering

@total_ordering
class MinType(object):
    def __le__(self, other):
        return True

    def __eq__(self, other):
        return (self is other)

Min = MinType()

然后使用排序键替换 Min 列表中的任何 None

mylist.sort(key=lambda x: Min if x is None else x)

原文由 augurar 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题