貌似diveintopython中关于__cmp__的解释不是很正确

本文探讨了Python中对象比较方法__cmp__与__eq__的区别及使用场景,通过实例对比了不同版本文档中的解释差异。

貌似diveintopython中关于__cmp__的解释不是很正确

找了dive into python的英文版本,关于 __cmp__的解释是这样的:
 
5.7. Advanced Special Class Methods
 
__cmp__ is called when you compare class instances. In general, you can compare any two Python objects, not just class instances, by using ==. There are rules that define when built-in datatypes are considered equal; for instance, dictionaries are equal when they have all the same keys and values, and strings are equal when they are the same length and contain the same sequence of characters. For class instances, you can define the __cmp__ method and code the comparison logic yourself, and then you can use == to compare instances of your class and Python will call your __cmp__ special method for you.
 
而在Python 2.5 Document中提及的是:
3.4.1 Basic customization


__lt__(self, other)
__le__(self, other)
__eq__(self, other)
__ne__(self, other)
__gt__(self, other)
__ge__(self, other)
New in version 2.1. These are the so-called ``rich comparison'' methods, and are called for comparison operators in preference to __cmp__() below. The correspondence between operator symbols and method names is as follows: x<y calls x.__lt__(y), x<=y calls x.__le__(y), x==y calls x.__eq__(y), x!=y and x<>y call x.__ne__(y), x>y calls x.__gt__(y), and x>=y calls x.__ge__(y).
A rich comparison method may return the singleton NotImplemented if it does not implement the operation for a given pair of arguments. By convention, False and True are returned for a successful comparison. However, these methods can return any value, so if the comparison operator is used in a Boolean context (e.g., in the condition of an if statement), Python will call bool() on the value to determine if the result is true or false.

There are no implied relationships among the comparison operators. The truth of x==y does not imply that x!=y is false. Accordingly, when defining __eq__(), one should also define __ne__() so that the operators will behave as expected.

There are no reflected (swapped-argument) versions of these methods (to be used when the left argument does not support the operation but the right argument does); rather, __lt__() and __gt__() are each other's reflection, __le__() and __ge__() are each other's reflection, and __eq__() and __ne__() are their own reflection.
Arguments to rich comparison methods are never coerced.
__cmp__(self, other)

Called by comparison operations if rich comparison (see above) is not defined. Should return a negative integer if self < other, zero if self == other, a positive integer if self > other. If no __cmp__(), __eq__() or __ne__() operation is defined, class instances are compared by object identity (``address''). See also the description of __hash__() for some important notes on creating objects which support custom comparison operations and are usable as dictionary keys. (Note: the restriction that exceptions are not propagated by __cmp__() has been removed since Python 1.5.)

dive into python中说:"你可以定义 __cmp__ 方法,自已编写比较逻辑,然后你可以使用 == 来比较你的类,Python 将会替你调用你的 __cmp__ 专用方法。"
而在Python 2.5 document里面是说:使用 == 来比较的时候,python会替你调用用 __eq__专用方法。而且貌似调用__cmp__的时候,当 xx == xx 为真的时候,__cmp__返回 零。
 
糊涂了...,不过感觉 Python 2.5 Document里面的解释比较正确。 

***************************************************

maillist里面的Tao Fei 给了个很好的例子:

__cmp__(        self, other)
Called by comparison operations if rich comparison (see above) is not defined.

应该是先找 __eq__ ,找不到在找 __cmp__
DiveIntoPython 的说法也许不够精确.
 不过也不能说它错.

>>> class A:
...         def __cmp__(self,other):
...                 print '__cmp__ is called'
...                 return 0
...
>>> a1 = A()
>>> a2 = A()
>>> a1 == a2
__cmp__ is called
True

>>> class A:
...         def __cmp__(self,other):
...                 print '__cmp__ is called'
...                 return 0
...         def __eq__(self,other):
...                 print '__eq__ is called'
...                 return True
...
>>> a1 = A()
>>> a2 = A()
>>> a1 == a2
__eq__ is called
True
>>>

<think>好的,我现在要回答用户关于Python中functools.cmp_to_key的问题。首先,我需要回忆一下这个函数的作用和用法。记得在Python 3中,sorted()和list.sort()不再支持cmp参数,而是只使用key参数。这时候,cmp_to_key的作用就是将旧式的比较函数转换成key函数,对吧? 接下来,我得确认用户可能的需求。他们可能之前用过Python 2,现在迁移到Python 3遇到了问题,或者看到旧代码中有cmp参数,想知道如何迁移。所以,我需要解释清楚为什么需要这个函数,以及如何使用它。 首先,我应该说明什么是比较函数。比较函数接受两个参数,返回负数、零或正数,表示第一个参数小于、等于或大于第二个参数。例如,在Python 2中可以用sorted(list, cmp=my_cmp)。但是在Python 3中,这被移除了,改为使用key函数,这通常更高效,因为每个元素的key只需要计算一次。 然后,我需要解释cmp_to_key如何将这样的比较函数转换为key函数。比如,用户有一个比较函数,想用sorted()的话,就需要用cmp_to_key包裹它,变成key参数的值。这时候,我应该给出一个具体的例子,比如排序数字时按照绝对值大小,但如果有相同的绝对值,正数排在前面。这时候比较函数可能需要比较两个数的绝对值和它们本身的正负。 接着,我需要详细说明步骤。先定义比较函数,然后用cmp_to_key转换,最后传给sorted的key参数。代码示例是必要的,这样用户能直观地看到如何应用。例如: def compare(a, b): if abs(a) < abs(b): return -1 elif abs(a) > abs(b): return 1 else: if a < b: return -1 else: return 1 然后转换并使用: from functools import cmp_to_key sorted_list = sorted([-3, 2, -1, 4], key=cmp_to_key(compare)) 结果应该是按照绝对值排序,但正数在相同绝对值时在前,所以得到[-1, 2, -3, 4]吗?需要验证一下这个例子是否正确。比如,绝对值顺序是1,2,3,4,那么元素是-1,2,-3,4。对的,所以结果应该是[-1,2,-3,4]。 然后,可能需要提醒用户,虽然cmp_to_key有用,但在可能的情况下应尽量使用key函数,因为比较函数每次比较都要执行,效率较低。比如,在绝对值排序的例子中,其实可以用key=lambda x: (abs(x), x) 来达到相同的效果,这样更高效。 最后,总结一下cmp_to_key的适用场景,比如当排序逻辑比较复杂,无法用简单的key表达式表示时,或者需要兼容旧代码时使用。同时,强调它在functools模块中,需要先导入。 在整理这些思路的时候,要确保术语正确,比如比较函数、key函数、返回值的含义等。另外,检查是否遗漏了重要的细节,比如转换后的key函数如何生成,内部如何工作的大致原理,可能不需要深入,但可以简单提及。 可能还需要提到cmp_to_key返回的是一个可调用对象,这个对象在排序时会被用来生成每个元素的键,但具体如何生成可能涉及到包装类和多个比较操作,这部分用户可能不需要了解,但知道它是如何桥接的比较函数和key机制即可。 最后检查有没有错误,比如在Python 3中是否确实移除了cmp参数,以及cmp_to_key的正确用法。同时,确保代码示例正确无误,能够实际运行并得到预期的结果。</think>下面是对Python中`functools.cmp_to_key`的逐步解释: --- ### 1. **背景:从`cmp`到`key`的转变** 在Python 2中,排序函数(如`sorted()`或`list.sort()`)支持`cmp`参数,允许用户传入一个**比较函数**,例如: ```python def compare(a, b): if a < b: return -1 elif a > b: return 1 else: return 0 sorted([5, 2, 3], cmp=compare) # 输出 [2, 3, 5] ``` 但在Python 3中,`cmp`参数被移除了,仅支持更高效的`key`参数(为每个元素生成一个键值,直接比较键值)。为了兼容旧代码,`functools.cmp_to_key`应运而生。 --- ### 2. **`cmp_to_key`的作用** **功能**:将旧式比较函数(`cmp`)转换为一个键生成函数(`key`),从而适配Python 3的排序逻辑。 - **比较函数**:接受两个参数`a`和`b`,返回: - **负数**:`a < b` - **0**:`a == b` - **正数**:`a > b` - **键函数**:接受一个参数`x`,返回一个可比较的键值(如整数、字符串、元组等)。 --- ### 3. **使用示例** 假设需按以下规则排序列表: 1. 按绝对值从小到大排列; 2. 若绝对值相同,正数排在负数前面。 #### 步骤1:定义比较函数 ```python def compare(a, b): abs_a, abs_b = abs(a), abs(b) if abs_a < abs_b: return -1 elif abs_a > abs_b: return 1 else: # 绝对值相同,正数在前 if a > b: return -1 else: return 1 ``` #### 步骤2:用`cmp_to_key`转换并排序 ```python from functools import cmp_to_key numbers = [-3, 2, -1, 4] sorted_numbers = sorted(numbers, key=cmp_to_key(compare)) print(sorted_numbers) # 输出 [-1, 2, -3, 4] ``` --- ### 4. **原理解析** `cmp_to_key`内部会生成一个包装类,通过多次调用比较函数,为每个元素生成一个**隐式键值**。排序时,直接比较这些键值(类似默认的`key`函数)。 --- ### 5. **何时使用`cmp_to_key`?** - **复杂排序逻辑**:当无法直接用`key=lambda x: ...`表达时(例如需要多条件动态比较)。 - **兼容旧代码**:迁移Python 2代码到Python 3。 --- ### 6. **性能注意** - **优先使用`key`**:直接定义键函数比`cmp_to_key`更高效(比较次数更少)。 - 上述示例可用`key`优化为: ```python sorted_numbers = sorted(numbers, key=lambda x: (abs(x), -x)) ``` --- ### 总结 `functools.cmp_to_key`是Python 3中兼容旧式比较函数的工具,适用于复杂排序场景或代码迁移。在可能的情况下,优先使用`key`参数以获得更好的性能。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值