42

I have a Python object with attributes a, b, c.

I still use old string formatting, so I'd normally print these manually:

 print 'My object has strings a=%s, b=%s, c=%s' % (obj.a, obj.b, obj.c)

Lately, my strings have been getting super long, and I'd much rather be able to simply pass the object into a string format function, something like:

 print 'My object has strings a=%a, b=%b, c=%c'.format(obj)

However, the syntax is incorrect. Is this possible?

Adam Hughes
  • 14,601
  • 12
  • 83
  • 122

6 Answers6

68

You can use the .attribute_name notation inside the format fields themselves:

print 'My object has strings a={0.a}, b={0.b}, c={0.c}'.format(obj)

Below is a demonstration:

>>> class Test(object):
...     def __init__(self, a, b, c):
...         self.a = a
...         self.b = b
...         self.c = c
...
>>> obj = Test(1, 2, 3)
>>> 'My object has strings a={0.a}, b={0.b}, c={0.c}'.format(obj)
'My object has strings a=1, b=2, c=3'
>>>

Note however that you do need to number the format fields when doing this. Also, as you can see, the str.format function has its format fields denoted by curly braces {...}, not the % sign.

For more information, here is a reference on the Format String Syntax in Python.

  • 12
    This looks better to me: `print 'My object has strings a={obj.a}, b={obj.b}, c={obj.c}'.format(obj=obj)` – Roman L Nov 07 '14 at 00:45
  • Awesome guys, thanks. Does the "0." (e.g. 0.a) denote the index of the item passed to format? – Adam Hughes Nov 07 '14 at 00:51
  • @AdamHughes - Exactly. Python begins numbering at `0` just like C/C++. `0` is the first (only) argument to `str.format`. –  Nov 07 '14 at 00:59
  • 1
    @RomanL - The OP disliked his current solution because it required you to type `obj` once per attribute. Writing `obj` that many times is tedious and unnecessary IMO. But, as you said, it is mainly a matter of preference. :) –  Nov 07 '14 at 01:01
  • That's right, but I still appreciate seeing the alternative approaches. I was unaware of both cases! – Adam Hughes Nov 07 '14 at 01:08
  • @iCodez: `0` and `obj` are repeated the same number of times within the string. A realistic example with a shortened obj: `'a={o.a}, b={o.b}'.format(o=my_actual_object_name)`. To someone not familiar with this notation this is much more obvious than `0.a` IMO. – Roman L Nov 07 '14 at 21:44
  • 8
    Also `'{a} {b}'.format(**vars(obj))` or `'{a} {b}'.format(**obj.__dict__)` – igniteflow Jun 01 '15 at 13:03
  • @iCodez can you this to access class methods as well? or just class attributes? – Halcyon Abraham Ramirez Aug 01 '15 at 03:48
  • 1
    @HalcyonAbrahamRamirez - You can access methods, yes, but you will not be able to call them. Instead, you will get a string representation of the method like: `>'`. –  Aug 05 '15 at 01:11
21

I think it's preferable to use vars() to access an object's attributes as a dict rather than usng __dict__.

So you could do this:

"My object has strings a={a}, b={b}, c={c}".format(**vars(obj))

For more background on why vars() is preferable to __dict__, see the answer to the question Use dict or vars()?.

Geoffrey Hing
  • 1,575
  • 2
  • 15
  • 22
7

As @igniteflow wrote in a buried comment:

'My object has strings a={a}, b={b}, c={c}'.format(**obj.__dict__)

With my limited python understanding: .__dict__ is a dict with all the instances attributes and the ** operator basically unpacks them and adds them as key=value args to the method

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
Christian
  • 3,551
  • 1
  • 28
  • 24
  • 2
    Nice! Using '**' is the key. Including .__dict__ in the example is unfortunate because it makes it look more complicated than it is. e.g. 'My object has strings a={a}, b={b}'.format(**{'a':'hi', 'b':'mom'}) – pythonjsgeo Oct 13 '15 at 02:17
2

For the sake of completeness, building on @igniteflow and @Christian, you could use the % string format operator and write:

'My object has strings a=%(a)s, b=%(b)s, c=%(c)s' % obj.__dict__
Jason
  • 413
  • 5
  • 11
1

Some of the suggested answers that rely on vars(...) don't work with immutable objects:

>>> class foo(object):
...   __slots__ = ()
...   def __init__(self):
...     self.x = 1
...
>>> vars(foo())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __init__
AttributeError: 'foo' object has no attribute 'x'

I think it's preferable to stick with something reliable and explicitly list what you need to be printed.

If you need to print a ton of attributes then storing those values as attributes might not be the best idea.

iggy
  • 1,613
  • 1
  • 18
  • 35
0

With Formatted String Literals :

>>> class A:
...     def __init__(self):
...             return
... 
>>> a = A
>>> a.value = 123
>>> f' a.value is: {a.value}'
' a.value is: 123

You can directly access attributes from objects in your namespace.

Erich
  • 1,902
  • 1
  • 17
  • 23