#python
Вопрос:
Как используется оператор тильды в Python?
Одна вещь, о которой я могу подумать, — это сделать что-то с обеих сторон строки или списка, например, проверить, является ли строка палиндромной или нет:
def is_palindromic(s):
return all(s[i] == s[~i] for i in range(len(s) / 2))
Есть еще какое-нибудь полезное применение?
Комментарии:
1. Обратите внимание, что оператор унарного дополнения
~
, реализованный специальным методом__invert__
, не связан сnot
оператором, что логически отрицает значение, возвращаемое__bool__
(или__nonzero__
в 2.x). Это также не связано с оператором-
унарного отрицания, реализованным__neg__
. Например~True == -2
, что не такFalse
или ложно, и-False == 0
, что все еще ложно.2. @eryksun, хотя то, что ты сказал, правильно (
-False==0
) Это сбивает с толку, так как вы говорили о том~
, и~False == -1
это не ложь.3. @Гильермеделазари, вторым примером было сравнение с арифметическим отрицанием (
__neg__
). Вероятно , мне следовало бы продолжить использоватьTrue
, например-True == -1
, значение, которое не равно -2 илиFalse
или ложно, что более четко связывает его с~True
результатом, а также с тем, что арифметическое отрицание abool
отличается от его логического отрицания. Я не пытался быть глубоким. Я просто выделил 3 операции и лежащие в их основе специальные методы, которые иногда путаются.4. См. также: tutorialspoint.com/python/python_basic_operators.htm — > Раздел «Побитовые операторы Python».
Ответ №1:
Это унарный оператор (принимающий один аргумент), заимствованный из языка Си, где все типы данных-это просто разные способы интерпретации байтов. Это операция «инвертирования» или «дополнения», при которой все биты входных данных меняются местами.
В 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:
Помимо того, что он является побитовым оператором дополнения, ~
он также может помочь вернуть логическое значение, хотя здесь это не обычный 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()]
Комментарии:
1.
numpy.NaN
кажется, это определяется какnumpy.float
. Если я попытаюсь~numpy.NaN
, python пожалуется, что унарный оператор~
не определен для типаnumpy.float
.2. @M. Херцкамп, это верно. NaN, Inf и-Inf являются частными случаями чисел с плавающей запятой. Инвертирование битов числа с плавающей запятой привело бы к бессмысленному результату, поэтому Python этого не позволяет. Вот почему вам нужно сначала вызвать .isnull() или np.isnan() в вашем массиве данных, а затем инвертировать полученные логические значения.
3. Обратите внимание, что
~True
это приводит к-2
, в то время как для логических значений numpy~np.True_
приводит кFalse
.4. хороший совет! Я видел, как он использовался здесь для сортировки набора данных: github.com/yu4u/age-gender-estimation/blob/master/create_db.py
Ответ №4:
Следует отметить, что в случае индексации array[~i]
массива reversed_array[i]
это равно . Это можно рассматривать как индексирование, начинающееся с конца массива:
[0, 1, 2, 3, 4, 5, 6, 7, 8]
^ ^
i ~i
Комментарии:
1. Это в основном потому, что значение, которое выходит
~i
(т. Е. отрицательное значение), действует как отправная точка для индекса массива, который python с радостью принимает, заставляя индекс оборачиваться и выбирать с обратной стороны.
Ответ №5:
Единственный раз, когда я когда-либо использовал это на практике, — это с 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
Ответ №6:
Я решал эту проблему с кодом leet и наткнулся на это прекрасное решение пользователя по имени Цитао Ван.
Проблема заключается в следующем: для каждого элемента в данном массиве найдите произведение всех оставшихся чисел без использования деления и во 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
Ответ №7:
Это незначительное использование-тильда…
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])