I have a list containing negative numbers, and want to encode the list with base64. How can I do that?
I tried:
l = [-10, -48, 100, -20] bytes(l)
But I get the error:
ValueError: bytes must be in range(0, 256)
I expect the same output as my Java code:
byte[] bytes = {-10, -48, 100, -20}; String result = Base64Utils.encodeToUrlSafeString(bytes); System.out.println(result); // 9tBk7A==
Advertisement
Answer
The error arises because Python expects unsigned 8-bit data, which can be obtained with the modulo %
operation:
unsigned == signed % 2 ** num_bits
import base64 def to_unsigned(x, num_bits=8): uplim_uint = 2 ** num_bits return x % uplim_uint l = [-10, -48, 100, -20] base64.b64encode(bytes(to_unsigned(x) for x in l)) # b'9tBk7A=='
This can also be hard-coded for performance:
l = [-10, -48, 100, -20] base64.b64encode(bytes(x % 64 for x in l)) # b'9tBk7A=='
To convert this back you need loop through base64.b64decode()
and convert the unsigned data back to signed reverting the %
with a ternary conditional operator:
signed == unsigned if unsigned < 2 ** (num_bits - 1) else unsigned - 2 ** num_bits
def to_signed(x, num_bits=8): half = 2 ** (num_bits - 1) uplim_uint = 2 * half return x if x < half else x - uplim_uint [to_signed(x) for x in base64.b64decode(b'9tBk7A==')] # [-10, -48, 100, -20]
or, hard-coding the function:
[(x if x < 128 else x - 256) for x in base64.b64decode(b'9tBk7A==')] # [-10, -48, 100, -20]