Python:Attrgetter,不处理任何值,可以在循环中使用

2024-03-29 13:59:47 发布

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

我有一个函数,它根据属性元组列表和反向布尔值重复排序,如下所示:

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与non-NoneType进行比较)。对于这种类型的问题,有很多关于stackoverflow的解决方案,建议用类似lambda x: (getattr(x, attr) is None, getattr(x, attr))的lambda函数替换attrgetter

不幸的是,这不适用于我,因为我正在排序的属性中可能有点,例如“attr_1.sub_attr_1”。operator.attrgetter支持这一点,但本机getattr当然不支持

关于如何在attgetter周围编写一个包装器来处理这个问题,或者如何编写一个可以在这里工作的自定义键函数,有什么建议吗?提前谢谢


Tags: lambda函数none属性排序operator建议reverse
1条回答
网友
1楼 · 发布于 2024-03-29 13:59:47

您可以使用另一个getter,它将返回一个键函数,该函数将生成元组(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>]

相关问题 更多 >