'Print a Python variable in hexadecimal by default
I wish to display some variables, data members in hexadecimal format any time they are printed.
My current approach is to define a class Hex:
class Hex:
"""Facilitate printing an integer in hexadecimal format."""
def __init__(self, data):
if not isinstance(data, int):
raise ValueError("Hex expects an integer.")
self._data = data
def __repr__(self):
return hex(self._data)
def __eq__(self, other):
return self._data == other
def __lt__(self, other):
return self._data < other
def __le__(self, other):
return self._data <= other
def __gt__(self, other):
return self._data > other
def __ge__(self, other):
return self._data >= other
def __add__(self, right):
return self._data + right
def __radd__(self, left):
return self._data + left
def __hash__(self):
return hash(self._data)
This works all right as the following examples demonstrate it:
address = Hex(0xdeadbeef)
record1 = {'address': address, 'counter': 42}
print(record1)
{'address': 0xdeadbeef, 'counter': 42}
The __hash__
is defined so that the object is hashable and can be used as a key in a dict:
record2 = {address: 'address'}
print(record2)
{0xdeadbeef: 'address'}
The equality and comparisons are defined so that handling of duplicates and sorting works:
list1 = [Hex(0xff), 15, 23, Hex(0xf), 255]
print(list1)
[0xff, 15, 23, 0xf, 255]
print(set(list1))
{15, 23, 0xff}
list1.sort()
print(list1)
[15, 0xf, 23, 0xff, 255]
The __add__
and __radd__
are defined so that pointer arithmetic is supported:
new_address = Hex(record1['address'] + 0x20400000)
print(new_address)
0xfeedbeef
address += 0x3f00
address += Hex(0xfe)
print(address)
0xdeadfeed
And now to the questions.
Is there a built in or existing hex integer that somehow has its own __repr__
attached that prints it in hex, but otherwise it would work as an int. I could not find such hence the above class.
The above pointer arithmetic works (subtraction, negation can be added similarly) and I was surprised that += works as well. Should I still add __iadd__
?
Should I add/override __new__
? Something like the following would not create duplicate instances for the same value:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, 'instances'):
cls.instances = {}
data = args[1]
if data in cls.instances:
return cls.instances[data]
# Create if not found:
inst = super(Hex, cls).__new__(cls) #, *args, **kwargs)
cls.instances[data] = inst
return inst
Any other suggestion to fix the class Hex or make it better?
Solution 1:[1]
Instead of creating a new class from scratch that holds an int (_data
), why don't you simply inherit from int and override the __repr__
method?
I wouldn't go as far as optimizing for duplicated values.
class Hex(int):
def __repr__(self):
return hex(self)
Edit -
Override the methods that return a new int with a call to super() and return as a Hex object. For example -
def __add__(self, val):
return Hex(super().__add__(val))
Looks a little verbose but it works. Plus you can write a monkey patcher that takes a list of all the operations you want to override -
ops = ['__add__', '__sub__', '__mul__']
def monkey_patch(operation: str):
"""
wraps Hex() around int's magic
method for provided operation.
"""
old_op = getattr(int, operation)
new_op = lambda self, val : Hex(old_op(self, val))
setattr(Hex, operation, new_op)
for op in ops:
monkey_patch(op)
This works -
>>> a = Hex(0xf)
>>> a += 1
>>> a
0x10
>>> a -= 1
>>> a
0xf
>>> a * 2
0x1e
Solution 2:[2]
How about inheriting from int?
>>> class Hex(int):
... def __repr__(self):
... return hex(self)
...
>>> a = Hex(123)
>>> a
0x7b
>>> a = Hex(16)
>>> a
0x10
>>> Hex(a + 2)
0x12
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Bharel |