Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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?
share|improve this question
up vote 3 down vote accepted

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.

share|improve this answer
    
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... – bitsmack yesterday
    
Maybe not as pretty as your first method, but a whole lot prettier than either of mine! :-D Thanks! – bitsmack yesterday
    
Glad to help, it was an very interesting question! – Simon yesterday
    
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. – Vatine yesterday
1  
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. – Peilonrayz yesterday

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.