TypeError is a Python exception that is raised when an operation is performed on objects of unsupported data types, for example, dividing an integer with a string (9/” home”). The TypeError exception we are discussing here concerns bytes and strings.
“TypeError: a bytes-like object is required, not str” is raised when we try to compare a string (str) object with a “byte” type object. Before we discuss the error, let’s discuss how to convert bytes to strings and vice-versa.
Converting Bytes to Strings and Vice Versa
The following Python codes explain different ways of converting bytes to strings, and vice versa (Figure 1 shows the difference between Bytes and Strings).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
## Convert String into Bytes in Python str1 = "Dell Latitude" byte1_a = b"Dell Latitude" # Encoding is "utf-8" by default byte1_b = bytes(str1, encoding="ascii") # Encoding is "utf-8" by default byte1_c = str1.encode("ascii") print(type(str1), type(byte1_a), type(byte1_b), type(byte1_c)) print(byte1_c) # Converting Bytes into a String object bytes2 = bytes("AFC Leopards", encoding="utf-8") print(type(bytes2)) # When decoding, you must use the encoding specified when encoding the string type string2_a = bytes2.decode(encoding="utf-8") string2_b = str(bytes2) print(type(string2_a), type(string2_b)) print(string2_a) |
Output:
<class 'str'> <class 'bytes'> <class 'bytes'> <class 'bytes'> b'Dell Latitude' <class 'bytes'> <class 'str'> <class 'str'> AFC Leopards
When printing the bytes in the above example, Python represented bytes as b’Dell Latitude’. In such a case, Python decoded the bytes to string under the hoods before printing so that we can read it; otherwise, by nature, they are not human-readable.
Reproducing and SolvingTypeError: a bytes-like object is required, not ‘str’
We will discuss 3 cases: the error when comparing two Python objects, reading data from a file, and using the socket module.
Case 1: Comparing Python objects
1 2 |
byte1 = bytes("20 Mt Everest", encoding="utf-8") print("Everest" in byte1) |
Output:
TypeError: a bytes-like object is required, not 'str'
In the code above, we are trying to check if a string (“Everest“) is in a byte string (byte1). Python does not support such kind of an operation. We can only compare string to a string and byte to a byte.
The Solution to Case 1
To solve case 1, we need to convert byte1 into a string before using the “in” comparison operator or vice versa (convert “Everest” into bytes).
1 2 3 4 |
byte1 = bytes("20 Mt Everest", encoding="utf-8") # converting byte1 into a string. print("Everest" in str(byte1)) |
Or
1 2 3 4 |
byte1 = bytes("20 Mt Everest", encoding="utf-8") # converting "Everest" into bytes. print(bytes("Everest", encoding="utf-8") in byte1) |
Output:
True
Now that the values on both sides of the “in” operator are of the same data type, the error is resolved.
Case 2: Error when reading data from a file
The Python open() function allows us to open files in different modes. Its general syntax is given by
open(file, mode=’r’,encoding=None, errors=None,…)
The mode parameter allows us to open a file in reading (r) or writing (w) mode. By default, reading/writing is done in string format, but we can issue the value “b” to read/write data in binary mode. Let’s see an example.
1 2 3 4 5 6 7 |
with open(file="example.txt", mode="rb") as infile: # Loop through the lines of the file for line in infile: # remove the new line character "\n" in the line line = line.strip() if "awk" in line: print(line) |
Output:
TypeError: a bytes-like object is required, not 'str'
In the above example, we are reading “example.txt” in binary mode (“r” for reading and “b” for binary in mode=”rb“). In binary mode, the contents loaded are bytes. That means that “awk” in line is trying to compare a string to bytes.
As said before, we cannot check if a string is contained in a bytes object because the two values are of different data types.
The solution to case 2
There are three solutions in this case. You can either load the file in string format (mode= “r“) or convert the string object to bytes within the for-loop or convert the bytes into a string, that is
1 2 3 4 5 6 7 8 |
# read file in string format, mode="r" with open(file="example.txt", mode="r") as infile: # Loop through the lines of the file for line in infile: # remove new line character "\n" in the line line = line.strip() if "awk" in line: print(line) |
Output:
awk 3
Or
1 2 3 4 5 6 7 8 |
with open(file="example.txt", mode="rb") as infile: # Loop through the lines of the file for line in infile: # remove new line character "\n" in the line line = line.strip() # convert the string "awk" to bytes by encoding it. if "awk".encode("utf-8") in line: print(line) |
Output:
b'awk 3'
Or
1 2 3 4 5 6 7 8 |
with open(file="example.txt", mode="rb") as infile: # Loop through the lines of the file for line in infile: # remove new line character "\n" in the line line = line.strip() # convert the bytes in the line into a string by decoding it. if "awk" in line.decode("utf-8"): print(line) |
Output:
b'awk 3'
Case 3: Error when using socket module
The socket.sendall(bytes[, flags]) expects bytes as the input. Therefore, if we pass a string into the function when sending data to a socket, we get the “TypeError: a bytes-like object is required, not ‘str'” exception. Here is an example of code reproducing this error.
1 2 3 4 5 6 7 8 9 10 |
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((“example.com”, 80)) # TypeError: a bytes-like object is required, not 'str' arises from here s.sendall(“GET https://example.com/example.txt HTTP/1.0\n\n”) ## << do something with the response here >> s.close() |
Output:
TypeError: a bytes-like object is required, not 'str'
The Solution to Case 3
There are two ways to solve the error in this case as well. First, we can solve the error by encoding the string to a bytes object before sending the data, that is,
1 2 3 4 5 6 7 8 9 10 |
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('example.com', 80)) # Encoding a string into bytes s.sendall(“GET https://example.com/example.txt HTTP/1.0\n\n”.encode('utf-8')) ## << do something with the response here >> s.close() |
Alternatively, we can convert the data we send into bytes by prefixing it with “b” – that is, b” GET https://example.com/example.txt HTTP/1.0\n\n”. That should solve the problem.
Note: Using the prefix “b” to convert string to bytes only works with literal strings (like the one above). If the string is stored in a variable, we need to use the .encode() method of conversion, instead.
Conclusion
TypeError: a bytes-like object is required, not ‘str’ is raised when we try to compare strings with bytes. The solution to this error is to convert the objects to be compared to be of the same data type, that is, strings to bytes or vice versa.