在Python 3中,list.sort()
方法将进行词典排序。但是在Python 3中,将列表与float
或int
进行比较会引发TypeError
,与Python 2不同,您可以在其中执行此操作:
>>> [0, 1] < 2
False
实现旧Python 2行为的最佳方法是什么?
我已经尝试了子类化list
,但为了实现这一点,必须将每个嵌套列表强制转换为子类类型,以便所有嵌套比较都使用重写的比较方法。有没有一种方法可以实现这一点,而不是通过递归方式将每个嵌套列表转换为子类?
我希望能够像这样比较两个列表:
>>> a = [[[0, 1], [2, 3]], [0, 1]]
>>> b = [[0, 1], [2, 3]]
>>> a < b
False
结果应该是False
,因为a[0][0]
是list
而b[0][0]
是int
,在我的情况下int
应该是始终被视为小于list
。
我希望实现一个与内置Python 3 list.sort
相同的排序函数,除非将list
与float
或{进行比较{1}},在这种情况下,int
应始终被视为更大。
答案 0 :(得分:1)
自as mentioned in the Python 2 docs:
以来内置类型的大多数其他对象比较不相等,除非它们是 同一个对象;选择是否一个对象被认为更小 或大于另一个是任意但一致的 一次执行程序。
对象比较仅在两个对象属于同一类型时才有意义。依赖于诸如[0, 1] < 2
之类的表达式返回的值不应该在程序中完成,这就是为什么从Python 3中删除了这种行为的原因。
为了进一步解释,如果你有列表[[[0, 1], [2, 3]], [0, 1]]
,这有两个要素:
[[0, 1], [2, 3]] and [0, 1]
。为了让python对它们进行排序,它会按字典顺序比较它们的内部值,因为它们都是第一个值为[0, 1] and [2, 3]
且第二个值为0 and 1
的列表。但是,它必须比较[0, 1] with 0
,它们不是同一类型,因此,比较会产生任意结果。
因此,此排序已被破坏。
如上所述,如果你有一些可以有意义地排序的列表和一些不能排序的列表(由于上面的解释),一个简单的解决方案是捕获可能的异常,然后返回False。
try:
[0, 1] < 2
except TypeError:
# return or assign False. True is not actually meaningful.
或者,对于list.sort()
try:
x.sort()
except TypeError:
pass # Do nothing. Python would produce meaningless results, anyway.
如果你想产生一个有意义的排序(如果这实际上有意义),那么你必须定义一个关键功能,如前所述。但这可能相当复杂。也许从不同的角度看你的问题会更好。
答案 1 :(得分:0)
正确的解决方案不是要list
的子类,而只是use the key
parameter of the sort
method to define a custom key function:
sorted(l, key=custom_key_function)
custom_key_function(list_element)
应为该list-element生成标准化密钥,所有密钥都属于同一类。
如果不确切知道您的列表可能包含哪些元素,我就不会推测如何实现它的更多详细信息,但我认为从您的示例中可以说您可能需要这样做是公平的。使用相同的custom_key_function
递归地对子列表进行排序。
答案 2 :(得分:0)
这是一个缓慢的方式。
要在不可比较的类型A
和B
之间添加顺序,请将它们的实例放在元组中:
a = [[[0, 1], [2, 3]], [0, 1]]
b = [[0, 1], [2, 3]]
def deep_annotate(item):
if isinstance(item, list):
return (1, [deep_annotate(i) for i in item])
else:
return (0, item)
deep_annotate(a) < deep_annotate(b)
#>>> False
deep_annotate(a) > deep_annotate(b)
#>>> True
不幸的是,很多这不是捷径,可以通过巧妙地使用cmp_to_key
来实现。