8

私はnamedtupleクラスをよく使います。私は今日、そのようなクラスにカスタムソートを実装する良い方法があるかどうかを考えていました。つまり、デフォルトのソートキーをnamedtupleの最初の要素(次に2番目、3番目など)ではなくします。

私の最初の本能は、実装__lt__して残り__eq__を任せるtotal_orderingことでした(le、ne、gt、geに記入します):

from collections import namedtuple
from functools import total_ordering


@total_ordering
class B(namedtuple('B', 'x y')):
    def __lt__(self, other):
        return self.y < other.y

でも:

def test_sortingB():
    b1 = B(1, 2)
    b2 = B(2, 1)
    assert b2 < b1  # passes
    assert b2 <= b1  # fails

ああ、そうです...他のメソッドが欠落している場合にtotal_orderingのみ記入します。tuple/namedtuple にはそのようなメソッドがあるため、total_ordering は何もしていません。

だから私は私のオプションは

  1. namedtuple の使用をやめて、退屈なクラスを独自に作成し、total_ordering を使用し続けます
  2. namedtuple を使い続け、6 つの比較メソッドすべてを実装する
  3. namedtuple を使用し続け、ソート値を最初のフィールドとして挿入します。幸いなことに、クラスのインスタンスはそれほど多くありませんが、通常はフィールドの順序に依存してフィールドを初期化するだけなので、面倒な場合があります。たぶんそれは悪い習慣です。

これを解決するための最良の方法に関する提案はありますか?

4

3 に答える 3

13

オプション 1. mixinを使用し、total_ordering をそれに適用する

@total_ordering
class B_ordering(object):
    __slots__ = ()                 # see Raymond's comment
    def __lt__(self, other):
        return self.y < other.y

class B(B_ordering, namedtuple('B', 'x y')):
    pass

オプション 2. に基づいて独自のデコレータを作成しtotal_ordering、代わりにそれを使用するだけです

于 2012-09-27T05:27:27.153 に答える
4

質問が示すように、名前付きタプルを代替キーで並べ替えることだけに関心がある場合は、次の関数でsort/sortedkey引数を使用してみませんか。attrgetter

>>> from collections import namedtuple
>>> from operator import attrgetter
>>> P = namedtuple("P", "x y") 
>>> p1 = P(1, 2)
>>> p2 = P(2, 1)
>>> sorted([p1, p2], key=attrgetter("y"))
[P(x=2, y=1), P(x=1, y=2)]

さらに進んで、独自のソート関数を定義できます。

>>> from functools import partial
>>> sortony = partial(sorted, key=attrgetter("y"))
>>> sortony([p1, p2])
[P(x=2, y=1), P(x=1, y=2)]
于 2012-09-27T06:17:31.387 に答える
1

私のアドバイスは、フィールドを並べ替えたい順序でnamedtupleを作成することです。値を作成するコードの部分を変更する必要がある場合があります (たとえば、 に変更someTuple("name", 24)someTuple(24, "name")ますが、通常、値は使用される場所よりも少ない場所で作成されるため、これはあまり大きな問題にはなりません。これにより、すべての比較メソッドを記述する手間が省け、おまけとして、これらのカスタム比較メソッドを常に呼び出すことによる追加のパフォーマンス オーバーヘッドも回避できます。

于 2012-09-27T04:59:41.170 に答える