45

I have a list of integer ASCII values that I need to transform into a string (binary) to use as the key for a crypto operation. (I am re-implementing java crypto code in python)

This works (assuming an 8-byte key):

key = struct.pack('BBBBBBBB', 17, 24, 121, 1, 12, 222, 34, 76)

However, I would prefer to not have the key length and unpack() parameter list hardcoded.

How might I implement this correctly, given an initial list of integers?

Thanks!

cubuspl42
  • 7,833
  • 4
  • 41
  • 65
mikewaters
  • 3,668
  • 3
  • 28
  • 22

6 Answers6

58

For Python 2.6 and later if you are dealing with bytes then a bytearray is the most obvious choice:

>>> str(bytearray([17, 24, 121, 1, 12, 222, 34, 76]))
'\x11\x18y\x01\x0c\xde"L'

To me this is even more direct than Alex Martelli's answer - still no string manipulation or len call but now you don't even need to import anything!

Scott Griffiths
  • 21,438
  • 8
  • 55
  • 85
  • 3
    For those who are wondering, Alex Martelli's answer does seem to run faster, at least with my benchmarks in Python 2.7.7. For 10,000 runs it's 12ms for his answer vs 18ms for this; these numbers are repeatable with little variation. Granted it's not a huge gain, just when working with a lot of data. That said, this answer is actually faster for me at 8ms: http://stackoverflow.com/a/12073686/353094 – leetNightshade Sep 01 '14 at 17:02
  • 3
    @leetNightshade That said in Python 3.4.1 x86 this method is the fastest according to my benchmarks. – leetNightshade Sep 01 '14 at 17:16
  • `>>> str(bytearray([42])) "bytearray(b'*')" >>> import sys; sys.version '3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:05:16) [MSC v.1915 32 bit (Intel)]'` – Cees Timmerman Jan 08 '19 at 13:34
51

I much prefer the array module to the struct module for this kind of tasks (ones involving sequences of homogeneous values):

>>> import array
>>> array.array('B', [17, 24, 121, 1, 12, 222, 34, 76]).tostring()
'\x11\x18y\x01\x0c\xde"L'

no len call, no string manipulation needed, etc -- fast, simple, direct, why prefer any other approach?!

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 2
    This makes the most sense to me, logically. Thanks for the tip! – mikewaters Aug 12 '10 at 18:54
  • 5
    the method `tostring()` is now deprecated since python 3.2. call `tobytes()` instead, which is a clearer name for what is actually happening. – TylerH Jan 04 '19 at 22:06
48

This is reviving an old question, but in Python 3, you can just use bytes directly:

>>> bytes([17, 24, 121, 1, 12, 222, 34, 76])
b'\x11\x18y\x01\x0c\xde"L'
Pi Delport
  • 10,356
  • 3
  • 36
  • 50
11
struct.pack('B' * len(integers), *integers)

*sequence means "unpack sequence" - or rather, "when calling f(..., *args ,...), let args = sequence".

7
key = "".join( chr( val ) for val in myList )
Katriel
  • 120,462
  • 19
  • 136
  • 170
1

Shorter version of previous using map() function (works for python 2.7):

"".join(map(chr, myList))

Xantium
  • 11,201
  • 10
  • 62
  • 89
Denis Shatov
  • 91
  • 1
  • 5