Toán tử dấu ngã trong Python


199

Cách sử dụng toán tử dấu ngã trong Python là gì?

Một điều tôi có thể nghĩ đến là làm một cái gì đó trong cả hai mặt của một chuỗi hoặc danh sách, chẳng hạn như kiểm tra xem một chuỗi có phải là palindromic hay không:

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

Bất kỳ cách sử dụng tốt khác?


11
Lưu ý rằng toán tử bổ sung đơn ~phương __invert__được thực hiện theo phương thức đặc biệt không liên quan đến nottoán tử, điều này phủ nhận một cách hợp lý giá trị được trả về bởi __bool__(hoặc __nonzero__trong 2.x). Nó cũng không liên quan đến -toán tử phủ định đơn nguyên, được thực hiện bởi __neg__. Ví dụ: ~True == -2không đúng Falsehoặc sai và -False == 0vẫn sai.
Eryk CN

@eryksun, mặc dù những gì bạn nói là đúng ( -False==0) Thật khó hiểu, vì bạn đã nói về ~, và ~False == -1đó không phải là Sai.
Guilherme de Lazari

3
@GuilhermedeLazari, ví dụ thứ hai là so sánh với phủ định số học ( __neg__). Có lẽ tôi nên tiếp tục sử dụng True, ví dụ -True == -1, không phải là -2 hoặc Falsesai, liên kết rõ ràng hơn với ~Truekết quả và cũng là phủ định số học của a boolkhác với phủ định logic của nó. Tôi đã không cố gắng để được sâu sắc. Tôi chỉ làm nổi bật 3 thao tác và các phương thức đặc biệt cơ bản đôi khi bị lẫn lộn.
Eryk CN

Câu trả lời:


192

Nó là một toán tử đơn nguyên (lấy một đối số) được mượn từ C, trong đó tất cả các loại dữ liệu chỉ là các cách khác nhau để diễn giải các byte. Đó là hoạt động "đảo ngược" hoặc "bổ sung", trong đó tất cả các bit của dữ liệu đầu vào được đảo ngược.

Trong Python, đối với các số nguyên, các bit của biểu diễn bổ sung twos của số nguyên được đảo ngược (như b <- b XOR 1đối với từng bit riêng lẻ) và kết quả được giải thích lại dưới dạng số nguyên bổ sung twos. Vì vậy, đối với số nguyên, ~xlà tương đương với (-x) - 1.

Các hình thức thống nhất của các ~nhà điều hành được cung cấp như operator.invert. Để hỗ trợ toán tử này trong lớp của riêng bạn, hãy cung cấp cho nó một __invert__(self)phương thức.

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

Bất kỳ lớp nào trong đó có ý nghĩa là có "bổ sung" hoặc "nghịch đảo" của một thể hiện cũng là một thể hiện của cùng một lớp là một ứng cử viên có thể cho toán tử nghịch đảo. Tuy nhiên, quá tải toán tử có thể dẫn đến nhầm lẫn nếu sử dụng sai, vì vậy hãy chắc chắn rằng nó thực sự có ý nghĩa trước khi cung cấp một __invert__phương thức cho lớp của bạn. (Lưu ý rằng chuỗi byte [ví dụ: '\xff'] không hỗ trợ toán tử này, mặc dù việc đảo ngược tất cả các bit của chuỗi byte là rất có ý nghĩa.)


16
Giải thích tốt, nhưng một lời cảnh báo - tất cả các khuyến cáo an toàn cho quá tải nhà điều hành áp dụng ở đây - đó không phải là một ý tưởng tốt, trừ khi nó phù hợp với dự luật một cách hoàn hảo.
Eli Bendersky

Phản hồi của Eli đã được đưa vào câu trả lời trong đoạn cuối.
wberry

91

~toán tử bổ sung bitwise trong python mà về cơ bản tính toán-x - 1

Vì vậy, một bảng sẽ trông như thế nào

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

Vì vậy, cho i = 0nó sẽ so sánh s[0]với s[len(s) - 1], cho i = 1, s[1]với s[len(s) - 2].

Đối với câu hỏi khác của bạn, điều này có thể hữu ích cho một loạt các vụ hack bitwise .


26

Bên cạnh việc là toán tử bổ sung bitwise, ~cũng có thể giúp hoàn nguyên giá trị boolean , mặc dù đây không phải là boolloại thông thường ở đây, thay vào đó bạn nên sử dụng numpy.bool_.


Điều này được giải thích trong,

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

Đôi khi đảo ngược giá trị logic có thể hữu ích, ví dụ, ~toán tử bên dưới được sử dụng để xóa dữ liệu của bạn và trả về cho bạn một cột không có 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.NaNdường như được định nghĩa là numpy.float. Nếu tôi thử ~numpy.NaN, python phàn nàn rằng toán tử unary ~không được định nghĩa cho kiểu numpy.float.
M.Herzkamp

2
@ M.Herzkamp, ​​đúng rồi. NaN, + Inf và -Inf là những trường hợp đặc biệt của số dấu phẩy động. Đảo ngược các bit của số dấu phẩy động sẽ tạo ra kết quả vô nghĩa, vì vậy Python không cho phép nó. Đó là lý do tại sao bạn cần gọi .isnull () hoặc np.isnan () trên mảng dữ liệu của bạn trước, sau đó đảo ngược các giá trị boolean kết quả.
geofflee

7
Lưu ý, điều đó ~Truedẫn đến -2, trong khi đối với booleans numpy ~np.True_kết quả False.
Christian Herenz

Mẹo tốt! Tôi thấy nó được sử dụng ở đây để sắp xếp thông qua bộ dữ liệu: github.com/yu4u/age-gender-estimation/blob/master/create_db.py
mLstudent33

19

Người ta cần lưu ý rằng trong trường hợp lập chỉ mục mảng, array[~i]số tiền là reversed_array[i]. Nó có thể được xem như là lập chỉ mục bắt đầu từ cuối mảng:

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

2
Chủ yếu là vì giá trị xuất phát ~i(tức là giá trị âm) đóng vai trò là điểm khởi đầu cho chỉ số mảng mà python vui vẻ chấp nhận khiến chỉ số quấn quanh và chọn từ phía sau.
hét

4

Lần duy nhất tôi từng sử dụng điều này trong thực tế là với numpy/pandas. Ví dụ, với .isin() phương pháp dataframe .

Trong các tài liệu họ chỉ ra ví dụ cơ bản này

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

Nhưng điều gì sẽ xảy ra nếu thay vào đó bạn muốn tất cả các hàng không nằm trong [0, 2]?

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

2

Tôi đã giải quyết vấn đề leetcode này và tôi đã tìm thấy giải pháp tuyệt vời này bởi một người dùng tên là Zitao Wang .

Vấn đề xảy ra như thế này đối với từng phần tử trong mảng đã cho, tìm sản phẩm của tất cả các số còn lại mà không sử dụng phép tính và O(n)thời gian

Giải pháp chuẩn là:

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 

Giải pháp của anh ta chỉ sử dụng một vòng lặp bằng cách sử dụng. Anh ta tính toán sản phẩm bên trái và sản phẩm bên phải khi đang sử dụng~

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

Đây là cách sử dụng nhỏ là dấu ngã ...

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]

đoạn mã trên là từ "Học trên máy"

bạn sử dụng dấu ngã (dấu ~) thay thế cho dấu chỉ mục dấu hiệu

giống như bạn sử dụng dấu trừ - dành cho chỉ số nguyên

Ví dụ)

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

là sự lấy mẫu như

print(array[~1])

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.