empty
empty

Reputation: 5434

How do I add __format__ to a namedtuple in Python 3.5+?

I'm working with code that was written for an earlier version of Python.

TensorShape = namedtuple('TensorShape', ['batch_size', 'channels', 'height', 'width'])

Later on, I have this (abridged) code:

s = [hdr, '-' * 94]
...
s.append('{:<20} {:<30} {:>20} {:>20}'.format(node.kind, node.name, data_shape,
                                                          tuple(out_shape)))

which blows up on tuple(out_shape) with the exception

TypeError: unsupported format string passed to tuple.__format__

because out_shape is a TensorShape and it doesn't have a __format__ method defined.

So I'm changing the definition of TensorShape to

def format_tensorshape(format_spec):
    return format("{0} {1} {2} {3}")

TensorShape = namedtuple('TensorShape', ['batch_size', 'channels', 'height', 'width'])
TensorShape.__format__ = format_tensorshape

But this code still blows up downstream with the same exception.

What am I doing wrong?

Upvotes: 2

Views: 651

Answers (2)

unutbu
unutbu

Reputation: 879421

You were on the right track -- just hook up the two arguments passed to format_tensorshape to your call to format:

import collections
def format_tensorshape(self, format_spec):
    return format("{0} {1} {2} {3}".format(*self), format_spec)

TensorShape = collections.namedtuple('TensorShape', ['batch_size', 'channels', 'height', 'width'])
TensorShape.__format__ = format_tensorshape

out_shape = TensorShape(1,2,3,4)
print('{:>20}'.format(out_shape))

yields

             1 2 3 4

Upvotes: 4

MSeifert
MSeifert

Reputation: 152647

You could simply use the formatting based on the string representation. That's possible with the !s conversion flag and because strings know how to interpret your formatting spec there is no need to create a custom __format__ method for your namedtuple:

s.append('{:<20} {:<30} {:>20} {!s:>20}'.format(node.kind, node.name, data_shape,
                                                tuple(out_shape)))
#                               ^^---- here I added the !s

For example:

>>> from collections import namedtuple
>>> TensorShape = namedtuple('TensorShape', ['batch_size', 'channels', 'height', 'width'])
>>> '{!s:>20}'.format(tuple(TensorShape(1,1,1,1)))
'        (1, 1, 1, 1)'

Upvotes: 2

Related Questions