<p>首先,如果你还没读过<a href="https://docs.python.org/3/howto/sorting.html" rel="nofollow">Sorting HOWTO</a>,一定要读它;它解释了很多起初可能并不明显的东西。在</p>
<hr/>
<p>对于第一个示例,两个IPv4地址,答案非常简单。在</p>
<p>要比较两个地址,一件显而易见的事情就是将它们从虚线的四个字符串转换成4个整数的元组,然后比较这些元组:</p>
<pre><code>def cmp_ip(ip1, ip2):
ip1 = map(int, ip1.split('.'))
ip2 = map(int, ip2.split('.'))
return cmp(ip1, ip2)
</code></pre>
<p>更好的方法是将它们转换为某种表示IP地址并具有比较运算符的对象。在3.4+中,stdlib内置了这样一个对象;让我们假设2.7也这样做了:</p>
^{pr2}$
<p>很明显,作为关键功能,这些功能更为简单:</p>
<pre><code>def key_ip(ip):
return map(int, ip.split('.'))
def key_ip(ip):
return ipaddress.ip_address(ip)
</code></pre>
<hr/>
<p>对于第二个例子,ham radio callsigns:为了编写<code>cmp</code>函数,您必须能够将每个ham地址分成字母、数字、字母部分,然后比较数字,然后比较第一个字母,然后比较第二个字母。为了编写<code>key</code>函数,必须能够将ham地址分解为字母、数字、字母部分,然后返回一个元组(数字、第一个字母、第二个字母)。同样,关键功能实际上是更容易,而不是更难。在</p>
<hr/>
<p>事实上,这是所有人都能想到的大多数例子的例子。大多数复杂的比较最终归结为一个复杂的部分序列的转换,然后对这个序列进行简单的词典编纂比较。在</p>
<p>这就是为什么<code>cmp</code>函数早在2.4就被弃用了,最后在3.0中被删除了。在</p>
<hr/>
<p>当然,在某些情况下,<code>cmp</code>函数更容易阅读,人们试图想出的大多数例子都是错误的,但也有一些。还有一些代码已经运行了20年了,没有人想用新的术语来重新考虑它而没有任何好处。对于这些情况,你有<a href="https://docs.python.org/2.7/library/functools.html#functools.cmp_to_key" rel="nofollow">^{<cd5>}</a>。在</p>
<hr/>
<p>实际上还有另一个原因<code>cmp</code>被否决,在这个原因之上,也许还有第三个原因。在</p>
<p>在Python2.3中,类型有一个<code>__cmp__</code>方法,用于处理所有运算符。在2.4中,他们将六种方法<code>__lt__</code>,<code>__eq__</code>等作为替代。这样可以获得更大的灵活性—例如,您可以使用未完全排序的类型。所以,2.3比较<code>a < b</code>,它实际上是在做<code>a.__cmp__(b) < 0</code>,它以非常明显的方式映射到<code>cmp</code>参数。但是在2.4+中,<code>a < b</code>做了<code>a.__lt__(b)</code>,这并没有。多年来这让很多人感到困惑,去掉{<cd7>}和{<cd1>}排序函数的参数消除了这种混乱。在</p>
<p>同时,如果您阅读排序HOWTO,您会注意到在<code>cmp</code>之前,完成这类操作的唯一方法是decorate sort undecorate(DSU)。请注意,如何将一个好的<code>key</code>函数映射到一个好的DSU排序(反之亦然)是盲目明显的,但是对于<code>cmp</code>函数来说,这绝对不明显。我不记得有人在py3k列表中明确提到过这一点,但我怀疑人们在决定是否最终永久性地杀死<code>cmp</code>时,可能已经有了这种想法。在</p>