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:
- The return value is a
str
object - The return value is prefixed with 0b
- Six
1's
and0'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.