Introduction

Computers work exclusively with binary values: 0 and 1, called bits. Every file on your computer is just a sequence of bits. Every message that gets sent between computers is just a sequence of bits. Python hides this from you most of the time–when you write True, 12, or "Chris", Python doesn’t normally show you the bits underneath. easybits provides the Bits class, which lets you see and manipulate those bits directly.

Creating bits

The Bits class can be built from several different kinds of values. The simplest is a string of 0 s and 1 s:

from easybits import Bits

b = Bits('1010')
print(b)  # 1010

You can also build bits from Python’s other building blocks. A boolean becomes a single bit:

Bits(True)   # 1
Bits(False)  # 0

Bytes become eight bits each:

Bits(b'a')  # 01100001

Booleans

Because Bits is built on top of the bitarray package, it supports the same bitwise operators you’d find in a lower-level language: ~ (NOT), & (AND), | (OR), ^ (XOR), and the shift operators << and >>:

a = Bits('1100')
b = Bits('1010')

a & b   # 1000
a | b   # 1110
a ^ b   # 0110
~a      # 0011
a << 1  # 1000
a >> 1  # 0110

Integers

Bits represent numbers in binary, where each position is worth twice as much as the position to its right: 1, 2, 4, 8, and so on. Because an integer’s bits don’t have a natural length the way a boolean’s single bit does, easybits requires you to say how many bits to use:

Bits(12, length=8)  # 00001100

Negative numbers are represented using two’s complement, which is why easybits always treats integers as signed. To recover the integer value of some bits, use the .int property:

b = Bits(-12, length=16)
b.int  # -12

You can add and subtract bits just like integers, as long as both operands have the same length:

Bits(5, length=8) + Bits(3, length=8)   # 00001000
Bits(5, length=8) - Bits(3, length=8)   # 00000010

This bitwise addition is implemented from scratch, carry bit and all, so you can watch how addition really happens at the level of circuits.

Text

Text is the trickiest of the three. ASCII, an early standard for representing text as bits, only has room for 128 characters–enough for English, but not for the world’s other languages, let alone emoji. Unicode, and its common encoding UTF-8, supports more than 150,000 characters, covering world languages and emoji alike. Because of this, encoding text requires choosing an encoding, and easybits lets you say which one to use:

Bits("Chris")                      # ASCII by default
Bits("\N{SMILING FACE WITH HEART-EYES}", encoding='utf8')

To go the other direction–from bits back to text–use the .ascii property, or decode the .bytes yourself with whichever encoding you used to create the bits:

b = Bits("Chris")
b.ascii  # 'Chris'

Inspecting bits

However you created your bits, you can always ask what they look like as a different kind of value, using the Bits properties:

  • .bool returns a list of booleans, one per bit

  • .int interprets the bits as a signed integer

  • .bytes returns the raw bytes

  • .ascii decodes those bytes as ASCII text

The API describes each of these, along with the rest of the Bits class, in full detail.