我在Python 3.5.1中有一个对象列表,其中包含几个命名属性。该列表表示一组C变量,因此每个对象有三个命名属性,对应于三种常见的基本类型:uint8,uint16和uint32。
class variableList(object):
def __init__(self, eight, sixteen, thirtytwo):
self.size_8 = eight
self.size_16 = sixteen
self.size_32 = thirtytwo
这些命名属性的值为(Nonetype) None
或(str)'E'
。对于每个对象,只有一个命名属性具有一些非None值。
我想对这个对象列表进行排序,使得size_32的非None值的所有对象都位于顶部,然后是size_16,后跟size_8。
在python 2.7.1中我成功地使用了它,但感觉就像是黑魔法:
size_filtered_list = sorted(filtered_list, key=lambda y: (y.size_32, y.size_16, y.size_8))
但在3.5.1中这不再适用。建议?
答案 0 :(得分:1)
您应该转向使用兼容类型;排序None
和'E'
是荒谬的,而Python 2"任意但一致的"不兼容类型的排序规则允许它,这是一种可怕的做法。如果唯一的值是None
和'E'
,那么它们实际上只是可怕的布尔值版本;您可以轻松使用False
和True
,并且您的key
函数在Py2和Py3中都能正常工作;你甚至可以优化"与operator.attrgetter
:
from operator import attrgetter
size_filtered_list = sorted(filtered_list, key=attrgetter('size_32', 'size_16', 'size_8'))
或者,使用原始基于lambda
的代码,您可以通过将None
替换为key
中的空字符串来使其工作,因此您可以比较兼容类型(同时仍然处理None
少于其他所有字符串):
size_filtered_list = sorted(filtered_list, key=lambda y: (y.size_32 or '', y.size_16 or '', y.size_8 or ''))
这有点愚蠢,但是None
和'E'
使用布尔数据也是如此。
答案 1 :(得分:0)
我只是为类实现比较运算符。假设您不希望根据存储在每个属性中的值进行排序,则此实现应该有效。
class variableList(object):
def __init__(self, eight, sixteen, thirtytwo):
self.size_8 = eight
self.size_16 = sixteen
self.size_32 = thirtytwo
def __lt__(self, other):
if self.size_8 is not None:
return self != other
elif self.size_16 is not None:
return True if other.size_32 is not None else False
else:
return False
def __eq__(self, other):
if self.size_8 is not None:
return other.size_8 is not None
elif self.size_16 is not None:
return other.size_16 is not None
else:
return other.size_32 is not None
为了完整起见,您还可以实现大于运算符,但不需要进行排序:
def __gt__(self, other):
if self.size_32 is not None:
return self != other
elif self.size_16 is not None:
return False if other.size_32 is not None else True
else:
return False
如果要对相同类型的值进行排序,则必须添加另一级别的嵌套来比较这些值。