【问题标题】:What is the meaning of "<" for Python dictionaries?Python 字典中的“<”是什么意思?
【发布时间】:2014-04-21 06:35:36
【问题描述】:

我注意到 Python 允许我这样做:

>>> {1: "foo"} < {2: "bar"}
True

它让我可以对列表、双端队列等做同样的事情。&lt; 在 Python 中应用于字典时的语义是什么?

一般来说,对于任何给定类型的集合,我在哪里可以找到&lt; 的语义?在大多数情况下,它似乎没有在文档中找到。例如:

>>> help(dict.__cmp__)

Help on wrapper_descriptor:

__cmp__(...)
    x.__cmp__(y) <==> cmp(x,y)

>>> help(cmp)

Help on built-in function cmp in module __builtin__:

cmp(...)
    cmp(x, y) -> integer

    Return negative if x<y, zero if x==y, positive if x>y.

我问是因为我有一个(int, dict) 形式的元组列表。我想根据第一个元素对这个数组进行排序,但是如果两个元素的第一个元素相等,那么我不关心第二个元素。我想知道myArray.sort() 是否会做一些复杂的事情,在这种情况下涉及通过字典递归,或者它是否只会返回一个任意值。

【问题讨论】:

  • 那么为什么不只对第一个元素进行排序呢?
  • 稍微复杂的代码。除非有必要,否则我更愿意避免复杂性。另外,我只是好奇。
  • 请注意,字典在 Python 3 中不再具有可比性。如果您执行dict1 &lt; dict2,您将获得TypeError。在您投入大量精力了解 Python 2 如何处理它们的细节之前,请记住这一点!
  • @Blckknght 谢谢!我可能永远没有理由使用 Python 3,但以防万一,了解这一点很有用。
  • @Nathaniel 从不说“从不”:)

标签: python python-2.7 python-internals


【解决方案1】:

引用comparison docs,

元组和列表

元组和列表使用对应元素的比较按字典顺序进行比较。这意味着要比较相等,每个元素必须比较相等,并且两个序列必须是相同的类型并且具有相同的长度。

如果不相等,则序列的排序与其第一个不同的元素相同。例如, cmp([1,2,x], [1,2,y]) 返回与 cmp(x,y) 相同的结果。如果对应的元素不存在,则先排序较短的序列(例如,[1,2]

字典

映射(字典)比较相等当且仅当它们的排序(键,值)列表比较相等。 (该实现有效地计算了这一点,而无需构造列表或排序。)除相等之外的结果是一致地解决的,但没有另外定义。 (早期版本的 Python [2.7.6 之前] 使用排序的 (key, value) 列表的字典比较,但这对于比较相等的常见情况来说非常昂贵。更早版本的 Python 仅通过身份比较字典,但这引起了意外,因为人们希望能够通过将字典与 {} 进行比较来测试字典是否为空。)

另外,找到this part of the documentation,专门比较序列类型与自身和其他类型,

序列对象可以与具有相同序列类型的其他对象进行比较。比较使用字典顺序:首先比较前两项,如果它们不同,则确定比较的结果;如果它们相等,则比较接下来的两项,依此类推,直到任一序列用完。如果要比较的两个项目本身是相同类型的序列,则以递归方式进行字典比较。如果两个序列的所有项比较相等,则认为序列相等。如果一个序列是另一个序列的初始子序列,则较短的序列是较小(较小)的序列。字符串的字典顺序使用单个字符的 ASCII 顺序。

请注意,比较不同类型的对象是合法的。结果是确定性但任意的:类型按名称排序。因此,列表总是比字符串小,字符串总是比元组小,等等。(不应该依赖比较不同类型对象的规则;它们可能会在未来的语言版本中改变.) 混合数值类型根据其数值进行比较,因此 0 等于 0.0,以此类推。

根据Python 2.7 source code,实际的字典比较是这样的

  1. 先比较key的长度。 (-1 如果第一个键较少,则返回 1,如果第二个键较少)

  2. 如果它们是相同的,那么它会尝试找到一个键,其中一个键在另一个中丢失或不同(这称为characterizing the dict

  3. 无论a, bb, a,它都会执行第2 步。如果其中任何一个为空,则假定两个字典相等。

  4. 现在,我们将通过对字典进行表征得到的差异进行比较,以获得实际的比较结果。

【讨论】:

  • 谢谢。我猜“始终如一地解决,但......没有另外定义”可能意味着它只是比较哈希值或类似的东西,而可能不会做任何愚蠢的事情每次都通过结构递归。但如果不进行分析或查看源代码,就很难知道。
  • @Nathaniel:字典没有哈希值。当 dicts 大小相同时,没有容易比较的值来产生排序结果;实现需要遍历两个 dicts 中的所有条目来计算相同大小案例的结果。你可以在这里看到代码:hg.python.org/cpython/file/e3217efa6edd/Objects/…
  • 请注意,== 比较由不同的函数 dict_richcompare 处理,它可以通过在发现差异后立即退出来避免一些工作:hg.python.org/cpython/file/e3217efa6edd/Objects/…
【解决方案2】:

喜欢@thefourtheye 的回答。

用python写的,可以这样解释:

def dict_compare(a, b):
    if len(a) != len(b):                # STEP 1: compare by length
        return -1 if len(a) < len(b) else 1

    res = 0
    akey, aval = characterize(a, b)     # Find first k, v that a[k] != b[k]
    bkey, bval = characterize(b, a)
    if akey is None:  # if no difference
        return 0
    if bkey is not None:               # STEP 2: compare by key
        res = cmp(akey, bkey)
    if res == 0 and bval is not None:  # STEP 3: compare by value
        res = cmp(aval, bval)
    return res

characterize 函数是这样的:

def characterize(a, b):
    """Find the first k that a[k] != b[k]"""
    akey, aval = None, None
    for k, v in a.items():
        if akey < k:
            continue
        if (k not in b) or (a != b[k]):
            akey, aval = k, v

    return akey, aval

【讨论】:

    猜你喜欢
    • 2010-09-29
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 2020-03-18
    • 2012-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多