Python 中的波形符运算符
Python 中波浪号运算符的用法是什么?
我能想到的一件事是在字符串或列表的两侧都做一些事情,例如检查字符串是否是回文:
def is_palindromic(s):
return all(s[i] == s[~i] for i in range(len(s) / 2))
还有其他好的用法吗?
What's the usage of the tilde operator in Python?
One thing I can think about is do something in both sides of a string or list, such as check if a string is palindromic or not:
def is_palindromic(s):
return all(s[i] == s[~i] for i in range(len(s) / 2))
Any other good usage?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
它是从 C 借用的一元运算符(采用单个参数),其中所有数据类型只是解释字节的不同方式。这是“反转”或“求补”操作,其中输入数据的所有位都被反转。
在Python中,对于整数,整数的二进制补码表示的位被反转(如
b <- b XOR 1
对于每个单独的位),结果再次解释为二进制补码整数。因此对于整数,~x
相当于(-x) - 1
。~
运算符的具体形式作为operator.invert
提供。要在您自己的类中支持此运算符,请为其提供一个__invert__(self)
方法。任何类中,如果实例的“补集”或“逆”是有意义的,而该实例也是同一类的实例,则该类是反转运算符的可能候选者。但是,如果误用,运算符重载可能会导致混乱,因此在向类提供 __invert__ 方法之前,请确保这样做确实有意义。 (请注意,字节字符串 [例如:
'\xff'
] 不支持此运算符,即使反转字节字符串的所有位是有意义的。)It is a unary operator (taking a single argument) that is borrowed from C, where all data types are just different ways of interpreting bytes. It is the "invert" or "complement" operation, in which all the bits of the input data are reversed.
In Python, for integers, the bits of the twos-complement representation of the integer are reversed (as in
b <- b XOR 1
for each individual bit), and the result interpreted again as a twos-complement integer. So for integers,~x
is equivalent to(-x) - 1
.The reified form of the
~
operator is provided asoperator.invert
. To support this operator in your own class, give it an__invert__(self)
method.Any class in which it is meaningful to have a "complement" or "inverse" of an instance that is also an instance of the same class is a possible candidate for the invert operator. However, operator overloading can lead to confusion if misused, so be sure that it really makes sense to do so before supplying an
__invert__
method to your class. (Note that byte-strings [ex:'\xff'
] do not support this operator, even though it is meaningful to invert all the bits of a byte-string.)~
是 python 中的按位补运算符,它本质上计算 < code>-x - 1因此,表格看起来像
这样,对于
i = 0
,它将比较s[0]
与s[len( s) - 1]
,对于i = 1
、s[1]
和s[len(s) - 2]
。至于您的其他问题,这对于一系列按位黑客很有用。
~
is the bitwise complement operator in python which essentially calculates-x - 1
So a table would look like
So for
i = 0
it would compares[0]
withs[len(s) - 1]
, fori = 1
,s[1]
withs[len(s) - 2]
.As for your other question, this can be useful for a range of bitwise hacks.
应该注意的是,在数组索引的情况下,
array[~i]
相当于reversed_array[i]
。可以看作是从数组末尾开始索引:One should note that in the case of array indexing,
array[~i]
amounts toreversed_array[i]
. It can be seen as indexing starting from the end of the array:除了作为按位求补运算符之外,
~
还可以帮助恢复 boolean 值,尽管它不是这里传统的bool
类型,而是您应该使用 numpy.bool_ 。这在反转逻辑值有时很有用中进行了解释
,例如,下面的
~
运算符用于清理数据集并返回不带 NaN 的列。Besides being a bitwise complement operator,
~
can also help revert a boolean value, though it is not the conventionalbool
type here, rather you should usenumpy.bool_
.This is explained in,
Reversing logical value can be useful sometimes, e.g., below
~
operator is used to cleanse your dataset and return you a column without NaN.我在实践中唯一一次使用过它是在 numpy/pandas 中。例如,使用
.isin()
数据框方法。在文档中,他们展示了这个基本示例
但是,如果您想要所有不在 [0, 2] 中的行怎么办?
The only time I've ever used this in practice is with
numpy/pandas
. For example, with the.isin()
dataframe method.In the docs they show this basic example
But what if instead you wanted all the rows not in [0, 2]?
解释为什么
-x -1
一般来说是正确的(对于整数)有时(示例),人们对 ~ 运算符的数学行为感到惊讶。例如,他们可能会认为,
~18
的结果应该是13
(因为bin (18)
给出'0b10010'
,反转这些位将给出 '0b01101',它代表13
- 对吧?)。或者他们可能期望237
(将输入视为带符号的8位数量),或与较大整数大小(例如机器字大小)相对应的其他正值。请注意,这里,
11101101
位的有符号解释(将其视为无符号,给出237
)是...-19 。对于更多位数也会发生同样的情况。事实上,只要我们使用至少 6 位,并将结果视为有符号,我们就会得到相同的答案:-19。
数学规则 - 取反,然后减一 - 适用于所有输入 - 只要我们使用足够的位,并将结果视为带符号的。
在 Python 中,从概念上讲,数字使用任意数量位。该实现将根据表示数字所需的空间自动分配更多空间。 (例如,如果该值“适合”一个机器字,则仅使用一个;该数据类型抽象了将数字符号扩展到无穷大的过程。)它也没有任何单独的无符号整数类型; Python 中的整数只是有符号的。 (毕竟,既然我们无法控制所使用的内存量,那么拒绝访问负值有什么意义呢?)
这打破了许多来自 C 环境的人的直觉,在 C 环境中这可以说是最佳实践仅使用无符号类型进行位操作,然后稍后应用 2s 补码解释(并且仅在适当的情况下;如果一个值被视为一组“标志”,则有符号解释不太可能有意义)。然而,Python 的
~
实现与其其他设计选择是一致的。如何强制无符号行为
如果我们想通过反转
18
的位来获得13
、237
或其他类似的值,我们需要一些外部机制指定要反转的位数。 (同样,18
概念上在其二进制表示中以任意位数具有任意多个 前导 0;将它们反转会导致前导 1 的结果;并将其解释为 2 秒补码会给出负结果。)最简单的方法是简单地屏蔽掉那些任意多的位。为了通过反转
18
得到13
,我们需要 5 位,因此我们用0b11111
进行掩码,即 31。更一般地说(并给出相同的结果)原始行为的接口):根据 Andrew Jenkins 在链接示例问题中的回答,另一种方法是直接与掩码进行异或。有趣的是,我们可以使用 XOR 来处理默认的任意精度情况。我们简单地使用任意大小的掩码,即概念上在其二进制表示中具有任意数量的
1
位的整数 - 即-1
。因此:然而,像这样使用 XOR 会产生负值的奇怪结果 - 因为 XOR 掩码“之前”(在更重要的位置)的所有任意多个设置位都没有被清除:
Explaining why
-x -1
is correct in general (for integers)Sometimes (example), people are surprised by the mathematical behaviour of the ~ operator. They might reason, for example, that rather than evaluating to
-19
, the result of~18
should be13
(sincebin(18)
gives'0b10010'
, inverting the bits would give '0b01101' which represents13
- right?). Or perhaps they might expect237
(treating the input as signed 8-bit quantity), or some other positive value corresponding to larger integer sizes (such as the machine word size).Note, here, that the signed interpretation of the bits
11101101
(which, treated as unsigned, give237
) is...-19
. The same will happen for larger numbers of bits. In fact, as long as we use at least 6 bits, and treat the result as signed, we get the same answer: -19.The mathematical rule - negate, and then subtract one - holds for all inputs - as long as we use enough bits, and treat the result as signed.
In Python, conceptually, numbers use an arbitrary number of bits. The implementation will allocate more space automatically, according to what is necessary to represent the number. (For example, if the value would "fit" in one machine word, then only one is used; the data type abstracts the process of sign-extending the number out to infinity.) It also does not have any separate unsigned-integer type; integers simply are signed in Python. (After all, since we aren't in control of the amount of memory used anyway, what's the point in denying access to negative values?)
This breaks intuition for a lot of people coming from a C environment, in which it's arguably best practice to use only unsigned types for bit manipulation and then apply 2s-complement interpretation later (and only if appropriate; if a value is being treated as a group of "flags", then a signed interpretation is unlikely to make sense). Python's implementation of
~
, however, is consistent with its other design choices.How to force unsigned behaviour
If we wanted to get
13
,237
or anything else like that from inverting the bits of18
, we would need some external mechanism to specify how many bits to invert. (Again,18
conceptually has arbitrarily many leading 0s in its binary representation in an arbitrary number of bits; inverting them would result in something with leading 1s; and interpreting that in 2s complement would give a negative result.)The simplest approach is to simply mask off those arbitrarily-many bits. To get
13
from inverting18
, we want 5 bits, so we mask with0b11111
, i.e., 31. More generally (and giving the same interface for the original behaviour):Another way, per Andrew Jenkins' answer at the linked example question, is to XOR directly with the mask. Interestingly enough, we can use XOR to handle the default, arbitrary-precision case. We simply use an arbitrary-sized mask, i.e. an integer that conceptually has an arbitrary number of
1
bits in its binary representation - i.e.,-1
. Thus:However, using XOR like this will give strange results for a negative
value
- because all those arbitrarily-many set bits "before" (in more-significant positions) the XOR mask weren't cleared:我正在解决这个leetcode问题,我遇到了这个漂亮的解决方案由名为 Zitao Wang 的用户创建。
问题是这样的,对于给定数组中的每个元素,在不使用除法的情况下,在
O(n)
时间内找到所有剩余数字的乘积标准解决方案是:
他的解决方案仅使用一个通过利用循环。他使用
~
即时计算左乘积和右乘积I was solving this leetcode problem and I came across this beautiful solution by a user named Zitao Wang.
The problem goes like this for each element in the given array find the product of all the remaining numbers without making use of divison and in
O(n)
timeThe standard solution is:
His solution uses only one for loop by making use of. He computes the left product and right product on the fly using
~
我发现波形符运算符的一个用途是将分数从某个基数转换为基数 10。
例如,假设您要将 0.01 从 5 进制转换为 10 进制。这样做的公式应该如下所示:
(0 * 5^0) + (0 * 5^-1) + (1 * 5^-2)
我们不需要费心计算整数部分,但是如果我们确实需要,代码可能如下所示:
integer = sum(digit * (5 ** exp) for exp, digital enumerate(reversed(str(integer)))
我们首先反转整数因为最小的指数是整数部分的末尾,即计算为 (x * 5^n) + (x * 5^n-1) + (x * 5^n-2) ...
至于分数,最大指数为所以我们不需要反转整数。但是如果我们尝试再次使用 enumerate 方法,它只会生成从 0 开始的正数
。可以做的是
for exp,enumerate(str(fraction)) 中的数字
,我们可以将digit
乘以5 ** -exp
我们需要从中减一。 -exp
使得 0 变成-1,1 变成-2,以此类推,所以我们可以写成digit * (5 ** -(exp+1))
我们。可以简单地替换-(exp+1)
~i
对于以下代码:fraction = sum(digit * (5 ** ~i) for exp, digital in enumerate(str(fraction))
这种方法特别适用当基数中的符号不是数字时很有用,例如使用 a、b、c、d 和 e 分别表示 0、1、2、3 和 4 的基数 5 系统。
One use I've found for the tilde operator is for converting a fraction from some base into base-10.
For instance, let's say you want to convert 0.01 from base-5 to base-10. The formula for doing so should look like this:
(0 * 5^0) + (0 * 5^-1) + (1 * 5^-2)
We don't need to bother with calculating the integer part, but if we did need to, the code could look like this:
integer = sum(digit * (5 ** exp) for exp, digit enumerate(reversed(str(integer)))
We reverse the integer first because the smallest exponents are at the end of the integer part i.e. the calculation goes (x * 5^n) + (x * 5^n-1) + (x * 5^n-2) ...
As for the fraction, the largest exponent is as the start of the fractional part. So we don't need to reverse the integer. But if we try to use the
enumerate
method again, it'll only generate the positive numbers from 0 onwards.What we can do instead is
for exp, digit in enumerate(str(fraction))
, we can multiplydigit
by5 ** -exp
. We need to subtract one from-exp
so that 0 turns into -1, 1 turns into -2, and so on, so we can writedigit * (5 ** -(exp+1))
. We can replace-(exp+1)
with simply~i
for the below code:fraction = sum(digit * (5 ** ~i) for exp, digit in enumerate(str(fraction))
This approach is particularly useful when the symbols in a base aren't numbers e.g. a base-5 system that uses a, b, c, d, and e to represent 0, 1, 2, 3, and 4 respectively.
引用文档
为了进一步完成工作,整数的波形符运算符记录在 https://docs.python.org/3.12/library/stdtypes.html#bitwise-operations-on-integer-types
这对我来说有点清楚。我有点困惑,因为在 Python 中整数默认是任意精度的,不像 C,我们通常有 32 或 64 位的整数大小,所以有点难以理解 Python 中二进制运算的含义。
关键见解的一部分是,在二进制补码中,您可以扩展:
当然,Python 不会存储无限多个 1 或 0在内存中:至少对于大整数来说,它必须做的是存储一个符号位和其余位。然后,当您执行
~
时,它只会翻转符号位和其他位。例如,考虑适合 2 的补码中的 3 位的整数:但是其中一些值也可以用两位而不是三位来表示:
但是无论我们使用多少位来表示每个整数,
~
都会结束无论如何,只要我们用无限多个相同的符号数字扩展,就会给出相同的-x-1
结果。Quote from the docs
Just to complete things further, the tilde operator is documented for integers at https://docs.python.org/3.12/library/stdtypes.html#bitwise-operations-on-integer-types
This clear's things up for me a bit. I was a bit confused because in Python integers are arbitrary precision by default, unlike C where we usually have integer sizes like 32 or 64 bits, so it is a bit hard to understand what binary operations mean in Python.
Part of the the key insight is that in two's complement you can extend:
Of course, Python doesn't store infinitely many one's or zeros in memory: what it must do, at least for large integers, is to store one sign bit and the rest of the bits. Then when you do
~
it just flips both the sign bit and the other bits. E.g. consider integers that fit into 3 bits in 2's complement:But some of those values can also be represented by two bits instead of three:
but no matter how many bits we use to represent each integer,
~
ends up giving the same-x-1
result anyways, so long as we extend with infinitely many of the same sign digit.它称为二进制补码 (~)
它返回数字的二进制补码。它翻转位。 2 的二进制是 00000010。它的补码是 11111101。
这是 -3 的二进制。所以,结果是-3。同样,~1 的结果是 -2。
输出:
2
同样,-3 的补码是 2。
it's called Binary One’s Complement (~)
It returns the one’s complement of a number’s binary. It flips the bits. Binary for 2 is 00000010. Its one’s complement is 11111101.
This is binary for -3. So, this results in -3. Similarly, ~1 results in -2.
Output :
2
Again, one’s complement of -3 is 2.
这是次要用法是波形符...
上面的代码来自“Hands On Machine Learning”,
您使用波形符(〜符号)作为替代品 - 符号索引标记
就像您使用减号一样 - 用于整数索引
ex)
与
打印(数组[~1])
This is minor usage is tilde...
the code above is from "Hands On Machine Learning"
you use tilde (~ sign) as alternative to - sign index marker
just like you use minus - is for integer index
ex)
is the samething as
print(array[~1])