Python bin(): Binary Values Handled with Ease

python bin function

The Python bin() method converts an integer value to a string representation of its binary representation. Python’s bin() method can also be used to return the binary representation of any object that has implemented a valid __index__ method.

The Python bin() built-in function is a useful tool in translating between languages, domains, and understanding the fundamentals of how low-level data is represented. In this article, you will learn the basic usage of the bin() function, some advanced uses, and ways in which one might break things using it.

TL;DR – The Python bin() function returns a string representation of an integer’s binary value.

# Define a number
>>> number = 42
42

# Use bin to get binary value
>>> bin(number)
0b101010

# Check the type
>>> type(bin(number))
<class 'str'>

# Only works for integers
>>> bin(42.0)
TypeError: 'float' object cannot be interpreted as an integer

Basic Use

The Python bin() function can be used for a range of applications where binary values are of interest. The simplest use-case is to return the binary value of an integer value—the only valid numerical representation for which the bin() function will accept. Let’s see that in action:

# Define a number
number = 42

# Get its binary value via bin()
bin_value = bin(42)

# Display the value, check the type
print(bin_value)
print(type(bin_value))

# Output
0b101010
<class 'str'>

A few things to note here:

  1. The return value is a str object
  2. The return value is prefixed with 0b
  3. Six 1's and 0's are used to represent values, the absolute minimum required.

Python’s bin() function will show you the binary representation of a number but there isn’t a lot you can do with that information explicitly. For example, let’s try to convert a binary string to a hexadecimal value:

# Convert to hexadecimal
hex_value = hex(bin_value)

# Result
TypeError: 'str' object cannot be interpreted as an integer

Yikes. So that isn’t great news but it is expected behavior given the implementation of the hex() function. Consider how the official Python documentation describes its use:

Convert an integer number to a lowercase hexadecimal string prefixed with “0x”. 

If our true goal was to get the hexadecimal value of 42 this would be a silly example—we’d just skip the bin() function altogether as such: hex(42). But we’re learning here, so let’s ignore that hiccup and see some more ridiculous examples.

Check out the article on how to convert hexadecimal values to binary in Python for more examples of how the bin() and hex() functions work in concert (also how they break things sometimes!)

Using Bin on Non-Integer Objects

Recall that Python represents all data an object. This is essential to understand how the Python bin() function will interact with other objects.  Some language features like operators and conditionals are special cases but, for everything else, Python models them as objects with a slew of attributes and methods available. For example, let’s check under the hood of our humble value 42 using the dir() method:

# Get a list of valid attributes for our int 'object'
>>> dir(42)

['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

Wow. There’s a lot going on here. Don’t worry I’m not going to try and unpack all that. Just know; everything in Python has a big long list of associated attributes and usually methods as well.

For now, the only attribute we’ll focus on is the __index__ attribute. This language feature was made available via PEP357 circa Python version 2.5 (early 2006) and is described as follows:

This PEP proposes adding … an __index__ special method so that arbitrary objects can be used whenever integers are explicitly needed in Python …

In other words, we can make any custom object work with the bin() function by implementing a custom __index__ method. Consider the following:

class CustomHex:
    """A custom hexadecimal representation of an integer"""
    def __init__(self, num: int):
        self.value = hex(num)


# Define an integer value
num = 42

# Show as built-in hex
print(hex(42))

>>> 0x2a

# Create custom hex object
better_hex = CustomHex(num)

# See hex value
print(better_hex.value)

>>> 0x2a

# Get binary value
print(bin(better_hex))

>>> TypeError: 'CustomHex' object cannot be interpreted as an integer

Here I’ve created a custom CustomHex class that converts an integer’s value and stores it internally as a hexadecimal string referenced by the object’s self.value attribute. When this object is passed to the bin() method it results in an TypeError.

This error results because our object doesn’t let Python know how it should be represented as an integer. Let’s see what happens when we implement a custom __index__ method as the documentation suggests:

class CustomHex:
    """A custom hexadecimal representation of an integer"""
    def __init__(self, num: int):
        self.value = hex(num)

    def __index__(self):
        """Custom method to define the integer representation"""
        return int(self.value, 16)


# Instantiate a new CustomHex object
better_hex = CustomHex(42)

# Get binary value
print(bin(better_hex))

>>> 0b101010

That’s a bingo! This example illustrates, albeit in another contrived imagining, how the bin() function can be coupled with the __index__ attribute to represent just about anything as a binary string in Python. Is this a common case? Not in my experience.

Common Cases

Python’s bin() function serves its purpose well. There are a number of common case uses in which this method is used. Whether you want to convert an int to a binary string, a string to binary, or a binary string to an int—the Python bin() built-in function can help. In some cases, it may require the use of other built-ins such as the hex() function to translate between values. Let’s take bin() out for a spin().

Convert an Int to Binary

Integers are the classic use case for Python’s bin() function. They can be used directly to extract a binary representation as such:

# Get the binary value of an integer
>>> bin(42)

0b101010

This returns a str object using as few 1’s and 0’s as possible. Note the prefix of 0b. There is no built-in way to remove that notation but, using string indexing, it can be done easy enough:

>>> bin(42)[2:]

101010

Easy enough. Let’s consider how one might return the binary representation of a string.

String to Binary

Keep in mind that everything in non-quantum computing boils down to 1’s and 0’s. Strings are no exception. The amount of 1’s and 0’s required to represent text quickly becomes impractical but can still be seen easily enough using Python’s bin() function. For this, we’ll have to use Python’s ord() function to get an integer value of each character in a string.

>>> "-".join(bin(ord(c))[2:] for c in 'overcoded')

1101111-1110110-1100101-1110010-1100011-1101111-1100100-1100101-1100100

(Uh oh, a one-liner.) Here I’ve created a binary string for the word overcoded with each character’s binary value separated by a single dash for visual clarity and dropped the leading 0b as well. The hoop-jumping of using the ord() function is, again, to satisfy Python’s bin() function’s need for an integer value.

Binary to Int

Python’s bin() function demands an integer value but can a binary value be easily converted into an integer? Let’s consider the binary string of the integer value 42 given to us by Python’s bin() function:

val = bin(42)
print(val, type(val))

>>> 0b101010 <class 'str'>

int(val)

>>> ValueError: invalid literal for int() with base 10: '0b101010'

It would seem that Python’s bin() function is good at giving orders regarding integer values but not so good at taking orders. Let’s see if we can come up with a work-around.

# Get the binary value of a number
bin_value = bin(42)
print(bin_value, type(bin_value))

0b101010 <class 'str'>

# Get Integer Value from Binary
int_value = int(bin_value, 2)
print(int_value, type(int_value))

42 <class 'int'>

# Convert int back to binary
bin_again = bin(int_value)
print(bin_again, type(bin_again))

0b101010 <class 'str'>

# Compare
print(bin_value == bin_again)

True

This circuitous sequence of events demonstrates the process of converting a binary value to an integer value in python and back again. I don’t know why one might want to do this but it does illustrate the underpinnings and interplay of Python’s bin and int features well.

Note: In using the int type to cast our binary string to an integer I used a second argument with the value 2. This instructs Python’s int that the first argument is a numerical representation in base 2 notation. If we’d been converting from hexadecimal a value of 16 would have been used. We have a useful article on how computers represent numbers if you want to learn more on that subject.

Convert Binary to String

Python’s bin() function can be used to convert a binary value, represented as a string of 1’s and 0’s or an integer value, to a string of characters. This involves some consideration for encoding, but I’m going to side-step most of that here. We’ll be assuming that ASCII characters are intended.

# Convert a binary value to a string
>>> str(1111010), type(str(1111010))

1111010, <class 'str'>

Well, that isn’t very useful. The issue here is that 1111010 looks like a binary value but, in fact, is an integer value. These values aren’t the same under the hood and we need to offer Python some clarification regarding our intent. Namely, we need to explicitly express that our integer value is to be interpreted as the binary notation for an ASCII-format character.

# Define a character
char = 'z'
print(char, type(char))

>>> z <class 'str'>

# Get the binary value
char_bin = bin(ord(char))
print(char_bin, type(char_bin))

>>> 0b1111010 <class 'str'>

# Convert binary repr to
# explict integer value
exp_int = int(char_bin[2:])
print(exp_int, type(exp_int))

>>> 1111010 <class 'int'>

# Interpret an integer representation
# of a binary value as actual binary
integer_value = int(str(exp_int), 2)
print(integer_value, type(integer_value))

>>> 122 <class 'int'>

# Convert our actual integer to an
# ASCII character
char_again = chr(integer_value)
print(char_again, type(char_again))

>>> z <class 'str'>

# Compare against initial value
print(char == char_again)

>>> True

I’ll be honest—that was a bit of a headache. The issue comes from trying to represent a binary value as that integer value explicitly. The binary value 1111010 does not equal the integer value of 1111010. Rather, the binary value 1111010 represents the integer value 122. Keep in mind, that’s because our initial binary value is in Base 2 notation. You can’t just magically represent a base 2 number as a base 10 value without undergoing some conversion process—at least not without corrupting data.

This example isn’t by any means reflective of any common case that I’ve come across. The most applicable use I can imagine would be for a script that accepted binary data as input and needed to convert it into a different notation. That’s a common enough requirement but I don’t often see engineers jumping into Python to accomplish such a feat.

Review

Python’s bin() function is a simple enough function but, as with many of the simple ones, there is more to the story. The cases of feeding bin() erroneously representative numbers (non-converted integer values for example) or objects without __index__ attributes implemented can wreak havoc and result in TypeErrors that aren’t always clear.

The utility bin() provides is incredibly useful as an introspective and learning tool. I’ve used it countless times to debug data from other projects (here’s looking at you, MIPS) and to automate the decoding of network transmission data. It’s not something that most applications need for real-time use but still, one of the many features that make Python one of the most versatile programming languages available today.

Zαck West
Full-Stack Software Engineer with 10+ years of experience. Expertise in developing distributed systems, implementing object-oriented models with a focus on semantic clarity, driving development with TDD, enhancing interfaces through thoughtful visual design, and developing deep learning agents.