4
\$\begingroup\$

My background is in C, and I'm finally learning this new-fangled "Python" that all the cool kids are talking about.

I want to create a list of formatted hexadecimal values like so:

['0x00','0x01','0x02','0x03' (...) '0xfe','0xff']

Please note that the leading zero's shouldn't be stripped. For example, I want 0x03, not 0x3.

My first successful attempt was this:

hexlist=list()
tempbytes = bytes(range(256))
for value in tempbytes:
 hexlist.append("0x" + tempbytes[value:value+1].hex())
del tempbytes

But, wow this is ugly. Then I tried to make it more Pythonic ("Pythony"?) like so:

hexlist = ["0x"+bytes(range(256))[x:x+1].hex() for x in bytes(range(256))]

My thoughts:

  1. OMG! That's harder to read, not easier!
  2. Not only that, but I had to invoke range twice, which I assume is inefficient.
  3. I bet there's a much better way that I haven't been exposed to yet...

My questions:

  1. Is the second much less efficient?
  2. Is there a better way to do this?
  3. What's the best thing to do here in keeping with python style?
asked Nov 16, 2016 at 4:10
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

The shortest and most readable way to do it would probably be

hexlist = [hex(x) for x in range(256)]

Time

Your first : 0.1 ms per loop for \10ドル^5\$ loops

Your second: 1 ms per loop for \10ドル^5\$ loops

The above : 0.02 ms per loop for \10ドル^5\$ loops


I'm unable to com up with a worse example, but there is always a worse way to do it, exactly as there is always preferable way to do it.

Edit To do this with filled zeros I would suggest to treat the first 10 numbers as a special case.

hexlist = [hex(x) if x > 15 else "{:#04x}".format(x) for x in range(256)]

new time: 0.04 ms. Even if it isn't as pretty.


Edit:

And when considering that format can format binary numbers, why not hex?

hexlist = ["{:#04x}".format(x) for x in range(256)]

I guess that this is hard coded for this range, but anyway.

Time: 0.1ms for per loop for \10ドル^5\$ loops.


And more edits

Using old style:.

hexlist = ["0x%02x" % n for n in range(256)]

Time: 0.08ms per loop for \10ドル^5\$ loops.


And specifically generating what we want.

hexlist = ["{:#04x}".format(x) for x in range(16)] + \
 [hex(x) for x in range(16, 256)]

Time: 0.03ms per loop for \10ドル^5\$ loops.

ferada
11.4k25 silver badges65 bronze badges
answered Nov 16, 2016 at 6:12
\$\endgroup\$
7
  • \$\begingroup\$ Excellent, Simon, thank you. Unfortunately, this strips off the leading zeros from the first 10 values. I wasn't clear in my question: I would like 0x03, for example, instead of 0x3. I've updated the question... \$\endgroup\$ Commented Nov 16, 2016 at 6:28
  • \$\begingroup\$ Maybe not as pretty as your first method, but a whole lot prettier than either of mine! :-D Thanks! \$\endgroup\$ Commented Nov 16, 2016 at 6:58
  • \$\begingroup\$ Glad to help, it was an very interesting question! \$\endgroup\$ Commented Nov 16, 2016 at 7:50
  • \$\begingroup\$ For roughly 0.13 ms per loop (over 10^5 loops), using "old-style" formatting strings, ["0x%02x" % n for in in range(256)] is short, readable and (probably) fast enough for once-off generation. \$\endgroup\$ Commented Nov 16, 2016 at 10:17
  • 2
    \$\begingroup\$ Both your edits are using the Format Specification Mini-Language, format(x, "#04x") is the same as "{:#04x}".format(x). Also either way you could change them to '0x{:0>{}x}'.format(5, 2), or "{:#0{}x}".format(5, 4) if you don't want a static length. \$\endgroup\$ Commented Nov 16, 2016 at 10:18

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.