Python.Attrgetter,处理None值,可以在循环中使用。处理None值的Attrgetter,可以在循环中使用。

问题描述 投票:1回答:1

我有一个函数,它可以根据属性和反向布尔值的元组列表进行反复排序,就像这样。

def multisort(lst, sorting):
  for attr, reverse in reversed(sorting):
    lst.sort(key=operator.attrgetter(attr), reverse=reverse)
  return lst

例如,输入排序变量的内容是这样的 [('attr_1', True), ('attr_2', False)].

我正在将代码升级到Py3,但这个方法已经不能用了,因为偶尔属性值是None(不能将NoneType和非NoneTypes进行比较)。 在stackoverflow上有很多解决这类问题的方法,建议把attrgetter换成lambda函数,如 lambda x: (getattr(x, attr) is None, getattr(x, attr)).

不幸的是,这对我来说是行不通的,因为我排序的属性中可以有点,例如'attr_1.sub_attr_1'。 operator.attrgetter支持这个,但当然原生的getattr不支持。

有什么建议可以让我写一个围绕attrgetter的封装器来处理这个问题,或者写一个自定义的键函数来处理这个问题? 先谢谢你。

python sorting
1个回答
1
投票

你可以使用一个替代的获取器,它将返回一个键函数,生成元组。(value is not None, value) (如果你想 None 要先来,这是Python 2的情况,它比什么都少)。)

import operator


def none_aware_attrgetter(attr):
    getter = operator.attrgetter(attr)
    def key_func(item):
        value = getter(item)
        return (value is not None, value)
    return key_func

def multisort(lst, sorting):
    for attr, reverse in reversed(sorting):
        lst.sort(key=none_aware_attrgetter(attr), reverse=reverse)
    return lst

一个运行样本。

class C:
    def __repr__(self):
        return f'<a1:{self.a1}, a2.s: {self.a2.s}>'

a = C()
b = C()
c = C()

a.a1 = 10
b.a1 = None
c.a1 = 0


a.a2 = C()
a.a2.s = 10

b.a2 = C()
b.a2.s = None

c.a2 = C()
c.a2.s = 0


lst = [a, b, c]
print(multisort(lst, [('a1', False)]))
# [<a1:None, a2.s: None>, <a1:0, a2.s: 0>, <a1:10, a2.s: 10>]

print(multisort(lst, [('a2.s', True)]))
# [<a1:10, a2.s: 10>, <a1:0, a2.s: 0>, <a1:None, a2.s: None>]
© www.soinside.com 2019 - 2024. All rights reserved.