Python中的代字号运算符


199

Python中的tilde运算符有什么用?

我能想到的一件事是在字符串或列表的两面都做一些事情,例如检查字符串是否为回文:

def is_palindromic(s):
    return all(s[i] == s[~i] for i in range(len(s) / 2)) 

还有其他好的用法吗?


11
请注意,~由特殊方法实现的一元补码运算符__invert__与该not运算符无关,后者在逻辑上取反了__bool__(或__nonzero__在2.x中)返回的值 。它也与所实现的-一元求反运算符无关__neg__。例如~True == -2,不是False或false,而-False == 0仍然是false。
Eryk Sun

@eryksun,尽管您说的是对的(-False==0)它令人困惑,因为您正在谈论~,而~False == -1这不是False。
Guilherme de Lazari

3
@GuilhermedeLazari,第二个示例是与算术求反(__neg__)比较。可能我应该继续使用True,例如-True == -1,它不是-2或Falsefalse,它可以更清楚地将其链接到~True结果,并且a的算术求bool反与其逻辑求反也不同。我不是想变得更深。我只是重点介绍了3种操作以及有时会混淆的底层特殊方法。
Eryk Sun '18

Answers:


192

它是从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__类提供方法之前这样做确实有意义。(请注意,字节字符串[ex:'\xff']不支持此运算符,即使将字节字符串的所有位取反也很有意义。)


16
一个很好的解释,但要提一个警告-在这里适用于操作员超载的所有安全免责声明-这不是一个好主意,除非它完全适合该法案。
伊莱·班德斯基

在最后一段中,Eli的反馈已纳入答案。
wberry 2012年

91

~是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 = 1s[1]s[len(s) - 2]

至于您的其他问题,这对于一系列按位破解可能很有


26

除了是按位补码运算符外,~还可以帮助还原布尔值,尽管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()]

numpy.NaN似乎被定义为numpy.float。如果我尝试了~numpy.NaN,python会抱怨说,~没有为type定义一元运算符numpy.float
M.Herzkamp

2
@ M.Herzkamp,没错。NaN,+ Inf和-Inf是浮点数的特殊情况。反转浮点数的位会产生无意义的结果,因此Python不允许这样做。这就是为什么您需要首先在数据数组上调用.isnull()或np.isnan(),然后反转结果布尔值。
geofflee,2017年

7
请注意,~True结果为-2,而numpy布尔值的~np.True_结果为False
Christian Herenz

好提示!我在这里看到它用于对数据集进行排序: github.com/yu4u/age-gender-estimation/blob/master/create_db.py
mLstudent33

19

应该注意的是,在数组索引的情况下,array[~i]等于reversed_array[i]。可以将其视为从数组末尾开始的索引:

[0, 1, 2, 3, 4, 5, 6, 7, 8]
    ^                 ^
    i                ~i

2
这主要是因为所产生的值~i(即负值)充当数组索引的起点,而python则乐于接受数组索引,从而使索引回绕并从背面进行拾取。
shriek

4

我在实践中唯一使用过此功能的时间是使用numpy/pandas。例如,使用.isin() dataframe方法

他们在文档中显示了这个基本示例

>>> 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

2

我正在解决这个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

-2

这是次要用法,是波浪线...

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]

上面的代码来自“动手学习机器”

您使用代字号(〜符号)替代-符号索引标记

就像您使用减号一样-用于整数索引

例如)

array = [1,2,3,4,5,6]
print(array[-1])

与...相同

print(array[~1])

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.