40

I have a string that can be a hex number prefixed with "0x" or a decimal number without a special prefix except for possibly a minus sign. "0x123" is in base 16 and "-298" is in base 10.

How do I convert this to an int or long in Python?

I don't want to use eval() since it's unsafe and overkill.

Hein
  • 1,397
  • 1
  • 9
  • 8
  • Why is eval unsafe? Are evil people going to sneak code into those numbers? Who has access to those strings? Are they untrustworthy? – S.Lott Mar 02 '09 at 22:12
  • 10
    eval is unsafe because it allows arbitrary code to be executed. If you are getting the string from a trusted source, it's still unsafe, it just so happens that you're relying on this trusted source to not take advantage of that. If you were always in control of the string, why was it a string? – Devin Jeanpierre Mar 02 '09 at 22:17
  • Your python program is available in source form -- it's "arbitrary code", also. Why draw a line between one set of Python source and another? Eval is no less safe than running the Python program in the first place. – S.Lott Mar 02 '09 at 22:20
  • 2
    No, python code is not safe, and this exact comment applies to importing arbitrary modules etc.. The assumption is that the python code is always written by you, and you trust you. If you're eval-ing a string written by you, why is it an eval at all? Thus my last statement in my reply. – Devin Jeanpierre Mar 02 '09 at 22:23
  • 1
    This conversation between S.Lott and Devin Jeapierre is what I see as a problem with the reputation system on SO. – mrduclaw Oct 02 '10 at 19:07
  • @DevinJeanpierre: *"If you were always in control of the string, why was it a string?"*: to allow dynamic code generation e.g., [`collections.namedtuple` implementation](http://hg.python.org/cpython/file/fe5c03fb0ff6/Lib/collections/__init__.py#l235). Though such high [level of magic](https://github.com/lihaoyi/macropy#levels-of-magic) is unnecessary in most cases. – jfs Sep 10 '13 at 05:25
  • @JFSebastian Eh, even namedtuple takes potential user input that it has to sanitize or else open a possible security hole. Circumstances where you want to use exec or eval without any possibility for user input at all are rare. – Devin Jeanpierre Sep 13 '13 at 15:57
  • @mrduclaw can you elaborate what the problem with rep system is in this context? – Ajay Brahmakshatriya May 08 '17 at 04:52
  • 1
    @AaronHall I think the duplicate target is not correct. Although the top answer there happens to mention the `int(..., 0)` solution, that's not what the OP asks for (for example with string `"10"` this should return 10, the other question should return 16) -- in fact I'd say that the `int(x,0)` method is wrong for the other question (for the reason above) – user202729 Aug 31 '18 at 00:37

5 Answers5

80
int("0x123", 0)

(why doesn't int("0x123") do that?)

Hein
  • 1,397
  • 1
  • 9
  • 8
  • 12
    It's just the way int is implemented in Python - it assumes decimal unless you explicitly tell it to guess by passing 0 as the radix. – David Z Mar 02 '09 at 23:04
  • 2
    Good, so leading zeros do not default it to oct. `int("010")` returns `10`. – Evgeni Sergeev Feb 04 '13 at 00:26
  • But Python does not represent octal numbers with a leading zero, they should have `0o` as the prefix (e.g. `0o10`). Still, the most common use-case is to convert from decimal numbers, and that is the default behavior. – Denilson Sá Maia Aug 09 '17 at 05:51
  • 1
    It would be better to pass 16 as the radix. – justinpc Jan 25 '21 at 19:50
38

Parse base 16 to an integer:

>>> int('0x123', 16)
291

Convert integer to a base 16 string:

>>> hex(291)
'0x123'
idmean
  • 14,540
  • 9
  • 54
  • 83
riza
  • 16,274
  • 7
  • 29
  • 29
5

Something like this might be what you're looking for.

def convert( aString ):
    if aString.startswith("0x") or aString.startswith("0X"):
        return int(aString,16)
    elif aString.startswith("0"):
        return int(aString,8)
    else:
        return int(aString)
S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • Why not use `if aString.upper().startswith('0X'):` That way you wouldn't need the or? of course `lower()` with `'0x'` also works. – a2j Jun 12 '12 at 03:36
  • @a2j: There's no great reason. What you can do, however, is use `timeit` to figure out what the tradeoffs are. – S.Lott Jun 13 '12 at 15:39
0

If you are doing a lot of go between with different number systems, the bitstring library make a lot of binary/Hex operations easier. It also supports string interpretation:

http://pythonhosted.org/bitstring/

Kirbinator
  • 213
  • 3
  • 8
-3

This is a simpler version which works like a charm. Returns string since hex() returns the same type:

def itoh(int): return hex(int)[2:]