19

我刚刚通过这个问题在 Python 中发现了按位补码一元运算,并且一直在尝试为它提出一个实际的应用程序,如果没有,确定将运算符重载(通过覆盖方法)用于其他用途是否通常是安全的. 问题中给出的示例以 . 失败,并且提供的链接似乎非常令人生畏。这里有一些摆弄,看看在使用中:__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)

我应该注意这个运算符的有效用例示例?即使有,对于除 之外的类型覆盖此运算符通常是否可以接受int

4

6 回答 6

14

按位非运算符的标准用例是按位运算,就像按位与&、按位或|、按位异或^和按位移位<<和一样>>。尽管它们很少用于更高级别的应用程序,但有时您仍需要进行按位操作,这就是它们存在的原因。

当然,您可以为自定义类型覆盖这些,并且通常在这样做时您不需要遵循任何特定的语义。只需选择对您的类型有意义的内容以及在某种程度上仍然适合操作员的内容。

如果操作晦涩难懂,最好用一两个词来解释,那么您应该改用标准方法。但是在某些情况下,尤其是在使用与数字相关的类型时,可能会有一些适合位运算符的类似数学的运算,因此可以使用这些运算。

就像您将覆盖标准运算符(例如+并且-仅用于有意义的操作)一样,您应该尝试对位运算符执行相同的操作。


~~True, ~~False给你的原因(1, 0)是因为bool类型没有定义自己的__invert__操作。但是,int确实;并且bool实际上是int. 所以bool实际上继承了所有按位和算术运算符的逻辑。这就是为什么True + True == 2等等。

于 2016-07-08T17:02:41.343 回答
6

我应该注意这个运算符的有效用例示例吗?即使有,对于 int 以外的类型覆盖此运算符通常是否可以接受?

通常,您不希望~仅仅因为它很有趣而使运算符重载。它使阅读变得困难。但有时,这种类型的重载int是有意义的。看看 SQLAlchemy 如何充分利用它。

于 2016-07-08T17:01:58.853 回答
3

它通常在代码高尔夫中用作一些事情的快捷方式,例如使用~x而不是-x-1~my_bool而不是not my_bool.

于 2016-07-08T19:41:22.097 回答
2

You can use that operator in conjunction with the negation operator (-) to increment a number by 1. For example:

x = 5
assert -~x == 6

This is the only practical way I've ever used the ~ operator. Any other way it is used for anything apart from numbers, is generally context dependent and often add a level of complexity to understanding code. For languages such as C++, Swift, Ruby, etc, you can overload this operator to mean anything which sometimes makes the code harder to digest quickly

于 2016-07-08T17:23:03.613 回答
0

正如其他人所提到的,遍历列表时它可以非常整洁。

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]

(此片段取自此处

于 2017-12-29T16:17:38.020 回答
0

某些方法(例如 String find())将返回 -1 表示“未找到”。这是因为字符索引 0 是有效的子字符串起始位置。因为整数是作为二进制补码存储的,所以 ~ 运算符可以巧妙地用于区分 -1 和其他所有内容。

例如:

test_sentence_1 = "There is a tilde in here"
test_sentence_2 = "There is not one in here"

if ~test_sentence_1.find('tilde'):
    print("1. Tilde Found")
else:
    print("1. Tilde NOT Found")

if ~test_sentence_2.find('tilde'):
    print("2. Tilde Found")
else:
    print("2. Tilde NOT Found")

1. Tilde Found
2. Tilde NOT Found
>>>

这是因为有符号整数被存储为二进制的补码,如果你将 -1 位翻转,这就是 '~' 所做的,那么你会得到 0,即 False。如果你翻转除-1之外的任何东西,你会得到一个非零,即真

波浪号的这种使用在 C 中很常见,其中许多函数会返回 -1 以指示失败

于 2021-06-15T12:34:48.213 回答