Python 中的波浪号运算符
- 2024-12-16 08:35:00
- admin 原创
- 151
问题描述:
Python 中波浪符号运算符有什么用途?
我能想到的一件事是在字符串或列表的两边做一些事情,比如检查字符串是否是回文:
def is_palindromic(s):
return all(s[i] == s[~i] for i in range(len(s) / 2))
还有什么好用途吗?
解决方案 1:
它是一个一元运算符(采用单个参数),借用自 C,其中所有数据类型都只是解释字节的不同方式。它是“反转”或“补充”运算,其中输入数据的所有位都被反转。
在 Python 中,对于整数,整数的二进制补码表示的位会被反转(就像b <- b XOR 1
每个单独的位一样),并且结果会再次解释为二进制补码整数。因此对于整数,~x
相当于(-x) - 1
。
运算符的具体化形式~
为operator.invert
。若要在您自己的类中支持此运算符,请为其提供一个__invert__(self)
方法。
>>> import operator
>>> class Foo:
... def __invert__(self):
... print 'invert'
...
>>> x = Foo()
>>> operator.invert(x)
invert
>>> ~x
invert
任何类中,如果实例的“补集”或“逆集”也是同一类的实例,则该类都可能适合使用反转运算符。但是,如果误用运算符重载,则会导致混淆,因此在__invert__
向您的类提供方法之前,请确保这样做确实有意义。(请注意,字节字符串 [例如:'xff'
] 不支持此运算符,即使反转字节字符串的所有位是有意义的。)
解决方案 2:
~
是Python 中的按位补码运算符,本质上是计算-x - 1
因此表格看起来就像
i ~i
-----
0 -1
1 -2
2 -3
3 -4
4 -5
5 -6
因此,对于,i = 0
它会s[0]
与s[len(s) - 1]
,对于i = 1
,s[1]
与进行比较s[len(s) - 2]
。
至于您的其他问题,这对于一系列按位黑客攻击非常有用。
解决方案 3:
需要注意的是,在数组索引的情况下,array[~i]
相当于reversed_array[i]
。它可以看作是从数组末尾开始索引:
[0, 1, 2, 3, 4, 5, 6, 7, 8]
^ ^
i ~i
解决方案 4:
除了作为按位补码运算符之外,~
还可以帮助恢复布尔值,尽管它不是bool
这里的常规类型,而是应该使用numpy.bool_
。
这是在以下位置解释的:
import numpy as np
assert ~np.True_ == np.False_
反转逻辑值有时很有用,例如,下面的~
运算符用于清理数据集并返回不包含 NaN 的列。
from numpy import NaN
import pandas as pd
matrix = pd.DataFrame([1,2,3,4,NaN], columns=['Number'], dtype='float64')
# Remove NaN in column 'Number'
matrix['Number'][~matrix['Number'].isnull()]
解决方案 5:
我在实践中使用过的唯一一次方法是numpy/pandas
。例如,使用.isin()
数据框方法。
在文档中他们展示了这个基本示例
>>> df.isin([0, 2])
num_legs num_wings
falcon True True
dog False True
但是如果您想要的是不在[0, 2] 中的所有行该怎么办?
>>> ~df.isin([0, 2])
num_legs num_wings
falcon False False
dog True False
解决方案 6:
解释为什么-x -1
通常是正确的(对于整数)
有时(例如),人们对 ~ 运算符的数学行为感到惊讶。例如,他们可能会推断-19
, 的结果~18
应该是,而不是13
(因为bin(18)
给出'0b10010'
,反转位将给出 '0b01101',这代表13
- 对吗?)。或者他们可能期望237
(将输入视为有符号的 8 位数),或者对应于更大整数大小(例如机器字大小)的其他正值。
请注意,此处位的有符号11101101
解释(如果视为无符号,则为237
)是... -19
。对于较大的位数,情况也是如此。事实上,只要我们使用至少 6 位,并将结果视为有符号,我们就会得到相同的答案:-19。
数学规则 - 取反,然后减一 - 适用于所有输入 - 只要我们使用足够多的位并将结果视为有符号的。
在 Python 中,从概念上讲,数字使用任意数量的位。实现将根据表示数字所需的内容自动分配更多空间。(例如,如果值“适合”一个机器字,则只使用一个;数据类型抽象了将数字符号扩展为无穷大的过程。)它也没有任何单独的无符号整数类型;整数在 Python 中只是有符号的。(毕竟,既然我们无论如何都无法控制使用的内存量,那么拒绝访问负值有什么意义呢?)
这打破了许多来自 C 环境的人的直觉,在 C 环境中,最佳实践可以说是仅使用无符号类型进行位操作,然后稍后应用 2s 补码解释(并且仅在适当的情况下;如果将值视为一组“标志”,则有符号解释不太可能有意义)。~
然而,Python 的实现与其其他设计选择一致。
如何强制未签名的行为
如果我们想通过反转 的位来获得13
或237
其他类似的东西18
,我们需要一些外部机制来指定要反转的位数。(同样,18
概念上, 在其二进制表示中以任意数量的位具有任意多个前导 0;反转它们将得到具有前导 1 的结果;而将其解释为二进制补码将得到负结果。)
最简单的方法是简单地屏蔽掉这些任意多的位。要从13
反转得到18
,我们需要 5 位,所以我们用 进行屏蔽0b11111
,即 31。更一般地说(并为原始行为提供相同的接口):
def invert(value, bits=None):
result = ~value
return result if bits is None else (result & ((1 << bits) - 1))
根据 Andrew Jenkins 在链接示例问题中的回答,另一种方法是直接与掩码进行异或。有趣的是,我们可以1
使用异或来处理默认的任意精度情况。我们只需使用任意大小的掩码,即一个在概念上在其二进制表示中具有任意位数的整数- 即-1
。因此:
def invert(value, bits=None):
return value ^ (-1 if bits is None else ((1 << bits) - 1))
但是,像这样使用 XOR 会产生奇怪的负结果value
- 因为 XOR 掩码“之前”(在更重要的位置)的所有任意设置位都没有被清除:
>>> invert(-19, 5) # notice the result is equal to 18 - 32
-14
解决方案 7:
我正在解决这道leetcode 问题,偶然发现了名叫Zitao Wang 的用户提供的这个漂亮的解决方案。
问题如下:对于给定数组中的每个元素,找到所有剩余数字的乘积,而不使用除法,并且O(n)
及时
标准解决方案是:
Pass 1: For all elements compute product of all the elements to the left of it
Pass 2: For all elements compute product of all the elements to the right of it
and then multiplying them for the final answer
他的解决方案只使用了一个 for 循环。他使用~
def productExceptSelf(self, nums):
res = [1]*len(nums)
lprod = 1
rprod = 1
for i in range(len(nums)):
res[i] *= lprod
lprod *= nums[i]
res[~i] *= rprod
rprod *= nums[~i]
return res
解决方案 8:
我发现波浪号运算符的一个用途是将某个底数的分数转换为十进制的分数。
例如,假设您要将 0.01 从 5 进制转换为 10 进制。执行此操作的公式应如下所示:
(0 5^0) + (0 5^-1) + (1 * 5^-2)
我们不需要计算整数部分,但如果我们需要的话,代码看起来可能是这样的:
integer = sum(digit * (5 ** exp) for exp, digit enumerate(reversed(str(integer)))
我们首先反转整数,因为最小的指数位于整数部分的末尾,即计算如下 (x 5^n) + (x 5^n-1) + (x * 5^n-2) ...
对于小数,最大的指数是小数部分的开始。所以我们不需要反转整数。但是如果我们enumerate
再次尝试使用该方法,它只会生成从 0 开始的正数。
我们可以做的是for exp, digit in 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, digit in enumerate(str(fraction))
当基数中的符号不是数字时,这种方法特别有用,例如,以 5 为基数的系统使用 a、b、c、d 和 e 分别表示 0、1、2、3 和 4。
解决方案 9:
它被称为二进制补码(〜)
它返回数字二进制的补码。它翻转位。2 的二进制为 00000010。它的补码为 11111101。
这是 -3 的二进制表示。因此,结果为 -3。类似地,~1 的结果为 -2。
~-3
输出 :2
再次,-3 的补数是 2。
解决方案 10:
这是次要用法,是波浪号......
def split_train_test_by_id(data, test_ratio, id_column):
ids = data[id_column]
in_test_set = ids.apply(lambda id_: test_set_check(id_, test_ratio))
return data.loc[~in_test_set], data.loc[in_test_set]
上述代码来自“Hands On Machine Learning”
您可以使用波浪符号(~ 符号)代替 - 符号索引标记
就像使用减号 - 用于整数索引一样
前任)
array = [1,2,3,4,5,6]
print(array[-1])
和
print(array[~1])
- 2025年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)