Operator tilde dengan Python

200

Apa gunanya operator tilde di Python?

Satu hal yang dapat saya pikirkan adalah melakukan sesuatu di kedua sisi string atau daftar, seperti memeriksa apakah string palindromik atau tidak:

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

Adakah penggunaan lain yang baik?

Clwen
sumber
11
Perhatikan bahwa operator komplemen unary ~diimplementasikan oleh metode khusus __invert__tidak terkait dengan notoperator, yang secara logis meniadakan nilai yang dikembalikan oleh __bool__(atau __nonzero__dalam 2.x). Ini juga tidak terkait dengan -operator negasi unary, diimplementasikan oleh __neg__. Misalnya ~True == -2, mana yang tidak Falseatau salah, dan -False == 0yang masih salah.
Eryk Sun
@eryksun, meskipun apa yang Anda katakan benar ( -False==0) Ini membingungkan, karena Anda berbicara tentang ~, dan ~False == -1yang tidak Salah.
Guilherme de Lazari
3
@GuilhermedeLazari, contoh kedua adalah membandingkan dengan negasi aritmatika ( __neg__). Mungkin saya harus terus menggunakan True, misalnya -True == -1, yang bukan -2 atau Falseatau salah, yang lebih jelas menghubungkannya kembali ke ~Truehasil dan juga bahwa negasi aritmatika dari a boolberbeda dari negasi logisnya. Saya tidak berusaha untuk mendalam. Saya baru saja menyoroti 3 operasi dan metode khusus yang mendasarinya yang terkadang membingungkan.
Eryk Sun

Jawaban:

192

Ini adalah operator unary (mengambil argumen tunggal) yang dipinjam dari C, di mana semua tipe data hanyalah cara yang berbeda untuk menafsirkan byte. Ini adalah operasi "membalikkan" atau "pelengkap", di mana semua bit data input dibalik.

Dalam Python, untuk bilangan bulat, bit representasi dua komplemen dari integer dibalik (seperti dalam b <- b XOR 1untuk setiap bit individu), dan hasilnya ditafsirkan lagi sebagai bilangan bulat dua komplemen. Jadi untuk bilangan bulat, ~xsama dengan (-x) - 1.

Bentuk reified ~operator disediakan sebagai operator.invert. Untuk mendukung operator ini di kelas Anda sendiri, berikan __invert__(self)metode.

>>> import operator
>>> class Foo:
...   def __invert__(self):
...     print 'invert'
...
>>> x = Foo()
>>> operator.invert(x)
invert
>>> ~x
invert

Kelas mana pun yang memiliki "pelengkap" atau "terbalik" dari instance yang juga merupakan instance dari kelas yang sama adalah kandidat yang memungkinkan untuk operator invert. Namun, overloading operator dapat menyebabkan kebingungan jika disalahgunakan, jadi pastikan bahwa sangat masuk akal untuk melakukannya sebelum memasok __invert__metode ke kelas Anda. (Perhatikan bahwa byte-string [ex: '\xff'] tidak mendukung operator ini, meskipun itu berarti untuk membalikkan semua bit dari byte-string.)

wberry
sumber
16
Penjelasan yang bagus, tetapi sepatutnya hati-hati - semua penafian keselamatan untuk overloading operator berlaku di sini - itu bukan ide yang baik, kecuali itu sesuai dengan tagihan.
Eli Bendersky
Umpan balik Eli telah dimasukkan ke dalam jawaban di paragraf terakhir.
wberry
91

~adalah operator komplemen bitwise dalam python yang pada dasarnya menghitung-x - 1

Jadi sebuah meja akan terlihat seperti

i  ~i  
0  -1
1  -2
2  -3
3  -4 
4  -5 
5  -6

Jadi untuk i = 0itu akan dibandingkan s[0]dengan s[len(s) - 1], untuk i = 1, s[1]dengan s[len(s) - 2].

Sedangkan untuk pertanyaan Anda yang lain, ini bisa berguna untuk serangkaian peretasan bitwise .

GWW
sumber
26

Selain menjadi operator komplemen bitwise, ~juga dapat membantu mengembalikan nilai boolean , meskipun ini bukan booltipe konvensional di sini, tetapi sebaiknya Anda gunakan numpy.bool_.


Ini dijelaskan dalam,

import numpy as np
assert ~np.True_ == np.False_

Membalikkan nilai logis kadang-kadang bisa berguna, misalnya, ~operator di bawah ini digunakan untuk membersihkan dataset Anda dan mengembalikan Anda kolom tanpa 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()]
Nicholas
sumber
numpy.NaNtampaknya didefinisikan sebagai numpy.float. Jika saya mencoba ~numpy.NaN, python mengeluh, bahwa operator unary ~tidak ditentukan untuk tipe numpy.float.
M.Herzkamp
2
@ M.Herzkamp, ​​itu benar. NaN, + Inf, dan -Inf adalah kasus khusus angka floating-point. Membalikkan bit angka floating point akan menghasilkan hasil yang tidak masuk akal, sehingga Python tidak mengizinkannya. Itu sebabnya Anda perlu memanggil .isnull () atau np.isnan () pada array data Anda terlebih dahulu, dan kemudian membalikkan nilai boolean yang dihasilkan.
geofflee
7
Catatan, yang ~Truemenghasilkan -2, sedangkan untuk booleans numpy ~np.True_menghasilkan False.
Christian Herenz
tip yang bagus! Saya melihatnya digunakan di sini untuk memilah-milah set
mLstudent33
19

Orang harus mencatat bahwa dalam kasus pengindeksan array, array[~i]berjumlah reversed_array[i]. Itu dapat dilihat sebagai pengindeksan mulai dari akhir array:

[0, 1, 2, 3, 4, 5, 6, 7, 8]
    ^                 ^
    i                ~i
Le Frite
sumber
2
Itu sebagian besar karena nilai yang keluar dari ~i(yaitu nilai negatif) bertindak sebagai titik awal untuk indeks array yang python dengan senang hati menerima menyebabkan indeks membungkus dan memetik dari belakang.
pekik
4

Satu-satunya waktu saya pernah menggunakan ini dalam praktek adalah dengan numpy/pandas. Misalnya dengan .isin() metode dataframe .

Dalam dokumen mereka menunjukkan contoh dasar ini

>>> df.isin([0, 2])
        num_legs  num_wings
falcon      True       True
dog        False       True

Tetapi bagaimana jika sebaliknya Anda menginginkan semua baris tidak pada [0, 2]?

>>> ~df.isin([0, 2])
        num_legs  num_wings
falcon     False       False
dog        True        False
Adam Hughes
sumber
2

Saya sedang memecahkan masalah leetcode ini dan saya menemukan solusi yang indah ini oleh seorang pengguna bernama Zitao Wang .

Masalahnya seperti ini untuk setiap elemen dalam array yang diberikan menemukan produk dari semua angka yang tersisa tanpa menggunakan divisi dan O(n) waktu

Solusi standar adalah:

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 

Solusinya hanya menggunakan satu untuk loop dengan memanfaatkan. Ia menghitung produk kiri dan produk kanan dengan cepat menggunakan~

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
Stuxen
sumber
-2

Ini adalah penggunaan minor ...

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]

kode di atas adalah dari "Hands On Machine Learning"

Anda menggunakan tilde (~ tanda) sebagai alternatif untuk - tanda indeks penanda

sama seperti Anda menggunakan minus - adalah untuk indeks integer

ex)

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

adalah samething as

print(array[~1])

hyukkyulee
sumber