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.
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
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
- The return value is prefixed with 0b
0'sare 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
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
# 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
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.
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
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
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
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.
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.
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.