Tilde `~` in python

At first I was like wtf is that?

The usage of a tilde symbol I was able to remember were:

  • creating negated (NOT) query  in django ORM like
from django.db.models import Q

# selects all poll objects with the publication year NOT EQUAL to 2005
Poll.objects.filter(~Q(pub_date__year=2005))
creating negated (NOT) query in django ORM
  • inverting boolean masks in pandas
#df = pd.DataFrame(...some data...)
# select all rows in which the column `content_type` contains the text `Specification`
df[df.content_type.str.contains('Specifications', case=False)]
# select all rows with no text `Specification` in the column named content_type
df[~df.content_type.str.contains('Specifications', case=False)]
inverting booleans masks in pandas library

In python ~ operator means bitwise NOT. It takes an integer and switch all bits 0 to 1 and 1 to 0. As wikipedia says `NOT x = -x − 1` (it's different for unsigned int but it's not our case). =>  ~0 = -0 - 1 = -1 and ~1 = -1 - 1 = -2

So in case of indexing a list the author of items[~index] wanted to take an element from the right side and use zero-based index from the right side too.

items = ['a', 'b', 'c', 'd', 'e', 'f']
#         0    1    2    3    4    5  # indexes
#        -6   -5   -4   -3   -2   -1  # negative indexes
#        ~5   ~4   ~3   ~2   ~1   ~0  # tilde indexes
items[0] == items[-6] == 'a'  # the first element
items[5] == items[-1] == 'f'  # the last element
items[~0] == items[-1] == 'f'
items[~1] == items[-2] == 'e'

It's a very strange way to do indexing. Please don't do that and just use minus indexes. It's much more common and easy to understand.

I have also learned that if you want to support ~ operator for your objects - you can implement magic method __invert__(self).