21

主に好奇心旺盛です。

(少なくとも py 2.6 と 2.7 では) afloatにはよく知られた豊富な比較関数 ( 、 、 など) がすべて__lt__()含ま__gt____eq__ていることに気付きました。

>>> (5.0).__gt__(4.5)
True

しかし、そうでintはありません

>>> (5).__gt__(4)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: 'int' object has no attribute '__gt__'

オペレーター自体が正常に動作するため、これは私にとって奇妙です

>>> 5 > 4
True

文字列でも比較機能をサポート

>>> "hat".__gt__("ace")
True

intしかし、持っているものはすべて__cmp__()

私には奇妙に思えるので、どうしてこうなったのだろうと思っていました。

テストしたばかりで、Python 3 で期待どおりに動作するため、いくつかのレガシーな理由を想定しています。それでもきちんとした説明を聞きたいのですが;)

4

3 に答える 3

21

Rich Comparisionsの PEP 207 を見ると、この興味深い文が最後にあります。

整数比較を扱う既に存在するインライン化は引き続き適用されるため、最も一般的なケースではパフォーマンス コストは発生しません。

したがって、2.x には整数比較の最適化があるようです。ソースコードを見ると、次のことがわかります。

case COMPARE_OP:
    w = POP();
    v = TOP();
    if (PyInt_CheckExact(w) && PyInt_CheckExact(v)) {
        /* INLINE: cmp(int, int) */
        register long a, b;
        register int res;
        a = PyInt_AS_LONG(v);
        b = PyInt_AS_LONG(w);
        switch (oparg) {
        case PyCmp_LT: res = a <  b; break;
        case PyCmp_LE: res = a <= b; break;
        case PyCmp_EQ: res = a == b; break;
        case PyCmp_NE: res = a != b; break;
        case PyCmp_GT: res = a >  b; break;
        case PyCmp_GE: res = a >= b; break;
        case PyCmp_IS: res = v == w; break;
        case PyCmp_IS_NOT: res = v != w; break;
        default: goto slow_compare;
        }
        x = res ? Py_True : Py_False;
        Py_INCREF(x);
    }
    else {
      slow_compare:
        x = cmp_outcome(oparg, v, w);
    }

したがって、2.x では既存のパフォーマンスの最適化 (C コードが整数を直接比較できるようにすること) があったようです。これは、豊富な比較演算子が実装されていた場合には保持されなかったでしょう。

現在 Python 3 では__cmp__サポートされていないため、豊富な比較演算子が必要です。現在、私が知る限り、これはパフォーマンスの低下を引き起こしません。たとえば、次のように比較します。

Python 2.7.1 (r271:86832, Jun 16 2011, 16:59:05) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.timeit("2 < 1")
0.06980299949645996

に:

Python 3.2.3 (v3.2.3:3d0686d90f55, Apr 10 2012, 11:25:50) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.timeit("2 < 1")
0.06682920455932617

したがって、同様の最適化が行われているように見えますが、私の推測では、後方互換性が考慮されている場合、それらすべてを 2.x ブランチに入れることはあまりにも大きな変更になるという判断が下されたのです。

2.x では、豊富な比較メソッドのようなものが必要な場合は、operatorモジュールを介して取得できます。

>>> import operator
>>> operator.gt(2,1)
True
于 2012-05-30T05:09:59.020 に答える
5

__cmp__()比較を行う昔ながらの方法であり、Python 2.1 でのみ導入された豊富な演算子(など) を支持して廃止されました。おそらく 2.7.x の時点では移行は完了していませんでしたが、Python 3.x では完全に削除されています。__lt____le____cmp__

Haskell には、私が見た中で最も洗練された実装があります。 (序数の) データ型になるには、 と がどのように機能Ordするかを定義するだけでよく、型クラス自体がとのデフォルトの実装を提供します。必要に応じて自分自身を定義することを歓迎します)。そのようなクラスを Python で自分で作成できますが、それがデフォルトではない理由はわかりません。おそらくパフォーマンス上の理由。<=<=>>=

于 2012-05-30T04:29:46.490 に答える
1

hircus が言ったように、__cmp__スタイル比較はPython 3の豊富な演算子( , …)を支持して非推奨になっています. Color クラスはandをサポートできましたが、 or ) はサポートできませんでした。そのため、豊富な比較演算子が追加され、下位互換性のために残されました。Python の哲学である「 1つ、できれば 1 つだけの明白な方法があるべきである」に従って、下位互換性が犠牲になる可能性があるため、レガシー サポートは Python 3 で削除されました。__lt____cmp____cmp__==!=<>__cmp__

Python 2 では、下位互換性を壊さないようにintまだ使用__cmp__されていますが、すべての浮動小数点数が他の浮動小数点数より小さい、大きい、または等しいというわけではありません (たとえば、 に(float('nan') < 0.0, float('nan') == 0.0, float('nan') > 0.0)評価されると(False, False, False)、何がfloat('nan').__cmp__(0.0)返されますか?)、したがってfloat、使用する必要があります。新しい豊富な比較演算子。

1 : Python シェルに「import this」と入力してみてください。

于 2012-05-30T05:15:01.463 に答える