patternpythonMinor
Advanced formatting with argument passing
Viewed 0 times
formattingargumentwithpassingadvanced
Problem
I want to customise how my objects are printed using the
I have two problems to make that happen in clear and concise way. But since the second one stems from the first one I'm presenting both here.
Formatting array
Passing options to
Produces:
What I want:
Doesn't work:
Leaves
Works but seems overly complex:
Formatting with non-uniform objects
The problem only gets compounded if the array elements don't always implement the format function, requ
.format() function.I have two problems to make that happen in clear and concise way. But since the second one stems from the first one I'm presenting both here.
Formatting array
Passing options to
.format() in array seems to me to be awfully messy if I want to match default behaviour with __repr__:import binascii
def format_data(data, formatstr):
if 'x' in formatstr:
return binascii.b2a_hex(data).decode('ascii')
else:
return repr(data)
class InsideA(object):
def __repr__(self):
return "InsideA()"
def __format__(self, _):
return "InsideA()"
class InsideB(object):
def __init__(self, data):
self.data = data
def __repr__(self):
data = format_data(self.data, 'x')
return "InsideB(data={0})".format(data)
def __format__(self, formatstr):
data = format_data(self.data, formatstr)
return "InsideB(data={0})".format(data)
if __name__ == "__main__":
a = InsideA()
b = InsideB(bytearray(b'test\xff\xff'))
array = [a, b]
print("what I want:")
print(array)
print("")
print("doesn't work:")
try:
print("{0:x}".format(array))
except Exception as e: # catch just to continue execution
print(e)
print("")
print("Leaves ' around elements:")
print(["{0:x}".format(elem) for elem in array])
print("")
print("Works but seems overly complex:")
print("[" + ", ".join("{0:x}".format(elem) for elem in array) + "]")Produces:
What I want:
[InsideA(), InsideB(data=74657374ffff)]
Doesn't work:
non-empty format string passed to object.__format__
Leaves
' around elements:['InsideA()', 'InsideB(data=74657374ffff)']
Works but seems overly complex:
[InsideA(), InsideB(data=74657374ffff)]
Formatting with non-uniform objects
The problem only gets compounded if the array elements don't always implement the format function, requ
Solution
list always uses repr on it's elements.When you
str or repr it.And internally
list is doing roughly the equivalent of what you are doing in format_array.The only way to make this work is to use something like
format_array,or subclass
list.But they will both be doing the same thing, just depends on how much sugar you want.
Your code is nice, readable and follows PEP8.
As this is tending towards example code, it's not in it's native environment, it's hard to comment distinctively on it.
But
format_data can be merged with the class.class InsideB(object):
def __init__(self, data):
self.data = data
def __repr__(self):
data = self._data(True)
return "InsideB(data={0})".format(data)
def __format__(self, formatstr):
data = self._data('x' in formatstr)
return "InsideB(data={0})".format(data)
def _data(self, as_hex):
if as_hex:
return binascii.b2a_hex(self.data).decode('ascii')
else:
return repr(self.data)You can then add an option to use 'hex' or
repr as the output type to the class.With the option to reverting to the original after a use.
Obviously it depends on your usage.
class InsideB(object):
def __init__(self, data, as_hex=False, revert_hex=False):
self.data = data
self._as_hex = as_hex
self.output_type = as_hex
self._revert_hex = revert_hex
def _data(self, as_hex):
if as_hex or self.output_type:
data = binascii.b2a_hex(self.data).decode('ascii')
else:
data = repr(self.data)
if self._revert_hex:
self.output_type = self._as_hex
return dataThen you would need to make a function that maps over all the items in the list,
changes
output_type to what you want, and you'll be in the same position as you are now.But with a bit more sugar.
If you choose to subclass list, and to use
str in __str__,then you'll get output which is just wrong.
>>> print('{!s}, {!s}'.format('a', 'b'))
a, b
>>> print('{!r}, {!r}'.format('a', 'b'))
'a', 'b'No matter how I look at it you wont be able to change the output 'nicely'.
Unless you think something more robust to
map(lambda i: i.output_type = True, array) is nice.Bottom line you have to manually implement this, as
repr is hard-coded.Code Snippets
class InsideB(object):
def __init__(self, data):
self.data = data
def __repr__(self):
data = self._data(True)
return "InsideB(data={0})".format(data)
def __format__(self, formatstr):
data = self._data('x' in formatstr)
return "InsideB(data={0})".format(data)
def _data(self, as_hex):
if as_hex:
return binascii.b2a_hex(self.data).decode('ascii')
else:
return repr(self.data)class InsideB(object):
def __init__(self, data, as_hex=False, revert_hex=False):
self.data = data
self._as_hex = as_hex
self.output_type = as_hex
self._revert_hex = revert_hex
def _data(self, as_hex):
if as_hex or self.output_type:
data = binascii.b2a_hex(self.data).decode('ascii')
else:
data = repr(self.data)
if self._revert_hex:
self.output_type = self._as_hex
return data>>> print('{!s}, {!s}'.format('a', 'b'))
a, b
>>> print('{!r}, {!r}'.format('a', 'b'))
'a', 'b'Context
StackExchange Code Review Q#113825, answer score: 3
Revisions (0)
No revisions yet.