Andy Hayden
Andy Hayden

Reputation: 375565

String substitution for object (non-dictionary)

Python has a great way to do string substitutions with a dictionary.
How can I replicate this same behaviour in my own object (rather than use a dictionary)?

In [1]: d = {'hello': 'world'}

In [2]: '%(hello)s' % d
Out[2]: 'world'

For example, if I have a class MyClass:

In [3]: class MyClass():
            a = 'x'
            b = 'y'

In [4]: m = MyClass()

Without any mapping, we expect string substitution to throw an error (and they do), but suppose I want it to act like {'a' : 'x'} i.e. have the following return 'x':

In [5]: '%(a)s' % m
TypeError: format requires a mapping

I've been messing around with format string syntax (__format__) or template string, without success.

How can I provide my class a "mapping" (dictionary?) to use in string substitution?

Upvotes: 1

Views: 375

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1122282

Your MyClass() instances do have a dictionary associated with them, access it with the vars() function:

'%(a)s' % vars(m)

This works for all custom classes that do not use a __slots__ attribute.

Alternatively, you can use the newer ''.format() string formatting method, which lets you access object attributes:

'{0.a}'.format(m)

It's this method of formatting that looks for a .__format__(format_spec) method on your custom classes, see the format() function documentation.

Last but not least, any object with a .__getitem__() method can be used for string formatting as if it is a dictionary:

>>> class Foo(object):
...     def __getitem__(self, name):
...         if name == 'bar': return 'baz'
...         raise AttributeError(name)
... 
>>> '%(bar)s' % Foo()
'baz'

Upvotes: 3

Related Questions