web-dev-qa-db-ja.com

Pythonでの '〜'(チルダ)演算子の適用

ビット単位の補数の単項演算 Python via this question )を発見し、実際のアプリケーションを考え出そうとしています。そうでない場合は、他の用途で(__invert__メソッドをオーバーライドして)演算子をオーバーロードしても安全かどうかを判断します。質問の例はTypeErrorで失敗し、 リンク 提供されたものはかなり威圧的なようです。使用中の~を確認するためにいじくり回します:

from bitstring import BitArray

x = 7

print(~x)
# -8

print(BitArray(int=x, length=4).bin)
# '0111'

print(BitArray(int=~x, length=4).bin)
# '1000'

print(~~True, ~~False)
# 1 0

for i in range(-100, 100):
    assert i + ~i == -1
    assert i ^ ~i == -1
    assert bool(i) == ~~bool(i)

私が知っておくべきこの演算子の有効なユースケースのanyの例はありますか?そして、存在する場合でも、int以外の型に対してこの演算子をオーバーライドすることは、一般的に許容されますか?

18
Alec

ビットごとのNOT演算子の標準的な使用例は、ビットごとの演算です。ビットごとのAND &、ビットごとのOR |、ビットごとのXOR ^、およびビット単位のシフト<<および>>。これらは高レベルのアプリケーションではめったに使用されませんが、ビット単位の操作を行う必要がある場合もあるので、なぜそこにあるのか。

もちろん、カスタムタイプの場合はこれらを上書きすることができ、一般的には、そうするときに特定のセマンティクスに従う必要はありません。自分のタイプにとって意味のあるものと、なんらかの方法で演算子にまだ適合するものを選択してください。

操作が曖昧で、Wordや2で説明した方がよい場合は、代わりに標準の方法を使用する必要があります。ただし、特に数値関連の型を使用する場合、ビットごとの演算子に適合する数学的な演算が発生する場合があるため、それらを使用しても問題ありません。

+-などの標準的な演算子を意味のある演算でのみ上書きするのと同じように、ビットごとの演算子についても同じことを行う必要があります。


~~True, ~~False(1, 0)を与える理由は、boolタイプが独自の__invert__オペレーションを定義していないためです。ただし、intにはあります。 boolは実際にはintのサブタイプです。したがって、boolは実際にはすべてのビット単位および算術演算子のロジックを継承します。だからTrue + True == 2など.

14
poke

私が知っておくべきこの演算子の有効なユースケースの例はありますか?そして、もしあるとしても、int以外の型のためにこの演算子をオーバーライドすることは一般的に受け入れられますか?

通常、~演算子は楽しいからといって過負荷にしたくないでしょう。読みにくくなります。ただし、このようなint以外の型のオーバーロードが意味をなす場合もあります。 SQLAlchemyがSQLAlchemyを活用する方法を見てください。

6
UltraInstinct

その演算子を否定演算子(-)と組み合わせて使用​​して、数値を1ずつインクリメントできます。次に例を示します。

x = 5
assert -~x == 6

これは、~演算子を使用した唯一の実用的な方法です。数値以外の場合に使用される他の方法は、一般にコンテキストに依存し、コードを理解するのにある程度の複雑さを追加することがよくあります。 C++、Swift、Rubyなどの言語では、この演算子をオーバーロードして、コードをすばやく消化するのを困難にすることを意味します。

2
smac89

これは、~xではなく-x-1または~my_boolではなくnot my_boolを使用するなど、いくつかのショートカットとして code golf で一般的に使用されます。

2
Justin

他の人が述べたように、リストをトラバースするときにそれは本当にきちんとすることができます。

for i in range(n):
    mylist[~i]
    #much prettier than mylist[-i-1]

マトリックスを時計回りに90度回転する例を見てみましょう。

def rotate( A):
    n = len(A)
    for i in range(n/2):
        for j in range(n-n/2):
            A[i][j], A[~j][i], A[~i][~j], A[j][~i] = \\
                     A[~j][i], A[~i][~j], A[j][~i], A[i][j]

(このスニペットは here から取得されました)

0
A73rnA