按可以是非的属性对列表排序

2024-05-19 16:35:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试使用

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

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

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

在Py2中这不是问题。在Py3里我该怎么处理?


Tags: keynamenone列表mysortoperatorlist
3条回答

排序比较运算符对Python 3中的类型更加严格,如here

The ordering comparison operators (<, <=, >=, >) raise a TypeError exception when the operands don’t have a meaningful natural ordering.

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)

对于一般解决方案,可以定义一个比任何其他对象都小的对象:

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()

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

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

这里提出的解决方案是可行的,但可以进一步缩短:

mylist.sort(key=lambda x: x or 0)

从本质上讲,我们不能把任何一个当作值为0的。

例如:

>>> mylist = [3, 1, None, None, 2, 0]
>>> mylist.sort(key=lambda x: x or 0)
>>> mylist
[None, None, 0, 1, 2, 3]

相关问题 更多 >