有没有办法创建一个不可排序的Python对象?
有没有办法创建一个在排序时会出错的 Python 对象?也就是说,当你试图对这些对象的列表进行排序时,会出现异常。我创建了一个非常简单的类,没有定义任何比较的方法,但这个类的实例还是可以比较和排序。可能是因为我的类从某个地方继承了比较的方法。但我并不想要这样的行为。
7 个回答
1
默认的列表排序是用内置的 cmp()
函数来比较列表里的元素。这个 cmp()
函数会检查它的两个参数(也就是你列表里的两个元素)是否有一个叫 __cmp__()
的方法。如果有,就用这个方法来进行比较。如果没有,就像你遇到的情况那样,使用这些元素的对象 ID(可以通过内置的 id()
函数得到)来进行比较。
如果你想让排序失败,可以定义一个比较方法,让它抛出一个异常:
>>> class X(object):
... def __cmp__(self, other):
... raise StandardError # or whatever Exception you need
...
>>> l = [X(), X(), X()]
>>> l.sort()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in __cmp__
StandardError
1
正如Will McCutchen提到的,你可以定义一个__cmp__
方法,让它抛出异常,这样就可以阻止普通的排序。大概是这样的:
class Foo(object):
def __cmp__(self, other):
raise Exception()
a = [Foo(), Foo(), Foo()]
a.sort()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __cmp__
Exception
不过,实际上你并不能完全阻止开发者对你的对象列表进行排序。因为使用list.sort()
或者内置的sorted()
函数时,任何人都可以通过自定义比较函数或者排序关键字来绕过__cmp__
方法。
# continuing from above
>>> a = [Foo(), Foo(), Foo()]
>>> a
[<__main__.Foo object at 0x1004a3350>, <__main__.Foo object at 0x1004a3390>,
<__main__.Foo object at 0x1004a33d0>]
>>> a.sort(key=id, reverse=True)
>>> # or a.sort(cmp=lambda a, b: cmp(id(b), id(a)))
>>> # or sorted(a, key=id)
>>> # etc...
[<__main__.Foo object at 0x1004a33d0>, <__main__.Foo object at 0x1004a3390>,
<__main__.Foo object at 0x1004a3350>]
正如其他人会指出的,我不太确定试图阻止别人对对象排序是否真的有意义。如果这不是出于好奇心,你想要解决的是什么实际问题呢?
7
你可以在这个类里定义一个 __cmp__
方法,然后每次调用它的时候都抛出一个异常。这样可能就能解决问题。
顺便问一下,为什么要这么做呢?