当前位置: 首页 > 面试题库 >

为什么这个用于对异类序列进行排序的键类的行为奇怪?

郁景龙
2023-03-14
问题内容

Python 3.X的sorted()功能不能被依赖于排序异质序列,因为大多数对不同类型的是unorderable(数字类型喜欢intfloatdecimal.Decimal等是一个例外):

Python 3.4.2 (default, Oct  8 2014, 08:07:42) 
[GCC 4.8.2] on html" target="_blank">linux
Type "help", "copyright", "credits" or "license" for more information.
>>> sorted(["one", 2.3, "four", -5])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: float() < str()

相反,没有自然顺序的对象之间的比较是任意的,但在Python 2.x中是一致的,因此sorted()可以:

Python 2.7.8 (default, Aug  8 2014, 14:55:30) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> sorted(["one", 2.3, "four", -5])
[-5, 2.3, 'four', 'one']

为了复制在Python 3.X的Python 2.x的行为,我写了一个类来用作key参数sorted(),这依赖于这样一个事实sorted()是保证只使用低于比较:

class motley:

    def __init__(self, value):
        self.value = value

    def __lt__(self, other):
        try:
            return self.value < other.value
        except TypeError:
            return repr(type(self.value)) < repr(type(other.value))

用法示例:

>>> sorted(["one", 2.3, "four", -5], key=motley)
[-5, 2.3, 'four', 'one']

到现在为止还挺好。

但是,当sorted(s, key=motley)某些包含复数的序列被调用时,我注意到了一个令人惊讶的行为:

>>> sorted([0.0, 1, (1+0j), False, (2+3j)], key=motley)
[(1+0j), 0.0, False, (2+3j), 1]

我会期望的0.0False并且1在一个组中(因为它们是可相互排序的),(1+0j)(2+3j)在另一个组中(因为它们是同一类型)。这个结果中的复数不仅彼此分开,而且其中一个位于彼此可比较但不与之可比的一组对象中间,这一事实有些令人困惑。

这里发生了什么?


问题答案:

您不知道比较按照什么顺序进行,甚至不知道比较哪些项目,这意味着您真的不知道您__lt__将产生什么样的效果。您定义的内容__lt__有时取决于实际值,有时取决于类型的字符串表示形式,但是在排序过程中,两个版本都可以用于同一对象。这意味着您的排序不仅由列表中的对象决定,而且还可能取决于它们的初始顺序。反过来,这意味着仅仅因为对象是可相互比较的,并不意味着它们将被排序在一起。它们之间可能被无法比拟的对象“阻挡”。

您可以通过放一些调试打印来查看正在比较的内容,以了解发生了什么:

class motley:

    def __init__(self, value):
        self.value = value

    def __lt__(self, other):
        fallback = False
        try:
            result = self.value < other.value
        except TypeError:
            fallback = True
            result = repr(type(self.value)) < repr(type(other.value))
        symbol = "<" if result else ">"
        print(self.value, symbol, other.value, end="")
        if fallback:
            print(" -- because", repr(type(self.value)), symbol, repr(type(other.value)))
        else:
            print()
        return result

然后:

>>> sorted([0.0, 1, (1+0j), False, (2+3j)], key=motley)
1 > 0.0
(1+0j) < 1 -- because <class 'complex'> < <class 'int'>
(1+0j) < 1 -- because <class 'complex'> < <class 'int'>
(1+0j) < 0.0 -- because <class 'complex'> < <class 'float'>
False > 0.0
False < 1
(2+3j) > False -- because <class 'complex'> > <class 'bool'>
(2+3j) < 1 -- because <class 'complex'> < <class 'int'>
[(1+0j), 0.0, False, (2+3j), 1]

例如,您可以看到基于类型的排序用于将复数与1进行比较,而不是用于对1和0进行比较。类似地,0.0 < False出于“正常”原因,但2+3j > False出于基于类型名称的原因。

结果是它排序1+0j到开头,然后离开2+3j它在False以上的位置。它甚至从未尝试将两个复数相互比较,并且将两者都比较的唯一项是1。

更一般而言,您的方法会导致不及物动的顺序,并为所涉及类型的名称提供适当的选择。例如,如果定义了类别ABC,使得A和C可以被比较,但比较B时的,然后通过创建对象它们引发异常ab以及c(从相应的类),使得c < a,可以创建一个周期a < b < c < a。 a < b < c这是正确的,因为将根据名称对类进行比较,但是c < a由于可以直接比较这些类型。使用不及物动词的顺序,就不可能有“正确的”排序顺序。

您甚至可以使用内置类型来执行此操作,尽管需要一些创意来思考类型名称按正确的字母顺序排列的对象:

>>> motley(1.0) < motley(lambda: 1) < motley(0) < motley(1.0)
True

(因为'float' < 'function':-)



 类似资料:
  • 我正在使用非负整数填充以下向量以解决代码阻塞问题: 以下排序方式导致提交失败: 但如果我只是按以下方式更改排序: 提交通过。 我用来排序的lamda函数有什么问题? 谢谢

  • 问题内容: 从版本8开始,Java具有 基于值的 类 的概念。这是为将来的版本做准备,该版本很可能将允许定义值类型。这两个定义/描述都提到了序列化(我加粗体): 关于现有的基于价值的类: 如果程序试图将两个引用区分为基于值的类的相等值,则可能会产生不可预测的结果,无论是直接通过引用相等还是间接地通过调用同步,标识哈希, 序列化 或任何其他标识敏感的机制。 关于未来价值类型: 可通过System.i

  • 问题内容: 我有可能需要按1-n键排序的大文件。其中一些键可能是数字键,有些则可能不是数字键。这是一个固定宽度的柱状文件,因此没有定界符。 有没有一种很好的方法可以用Unix排序呢?使用一个键,就像使用“ -n”一样简单。我已经阅读了手册页并简短地搜索了Google,但是没有找到一个很好的例子。我将如何实现这一目标? 注意:由于文件大小可能,我排除了Perl。这将是不得已的办法。 问题答案: 使用

  • 问题内容: 假设我们在集合中有一些项目,并且我们想使用某些比较器对它们进行排序,并期望结果在列表中: 一种方法是对列表中的项目进行排序,例如: Anothe方法正在使用排序流: 我想知道哪种方法更有效?排序流是否有任何优势(例如在多核上进行Faste排序)? 在运行时复杂性方面/最快方面是高效的。 我不相信自己要实现一个完美的基准,学习并不能真正启发我。 问题答案: 可以肯定地说,两种形式的排序都

  • 我有一个名为map的HashMap,它将字符存储为键,将整数存储为值,然后使用以下代码将其存储到名为entries的ArrayList中: 现在我正在尝试根据整数值而不是键对这些条目进行排序。我试图使用一个lambda表达式来实现比较器接口,但它不起作用。这是我的代码: 以下是我得到的错误: 这一行有多个标记 > 语法错误,插入“)”以完成表达式 类型集合中的方法sort(列表,比较器)不适用于参

  • 我从课本上抄了一个例子,但它拒绝编译。我是不是在什么地方打错了?出于某种原因,在客户端代码中,collections.sort(words)不允许程序编译。任何帮助都很感激。代码复制自Stuart Reges和Marty Stepp的“构建Java程序”第二版。我正试图通过复制来理解它。 该程序应该将一个CalendarDate对象装入一个ArrayList中。通过实现CalendarDate的可