我有一个函数,它可以根据属性和反向布尔值的元组列表进行反复排序,就像这样。
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的封装器来处理这个问题,或者写一个自定义的键函数来处理这个问题? 先谢谢你。
你可以使用一个替代的获取器,它将返回一个键函数,生成元组。(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>]