2

If i define the below custom class in Python:

class Test:
    hey = 'ho'
    yo = 'go'
    fo = 'sho'

Is there any way when using the string format() method to only have to pass in my object once and to then access that in all the arguments. Ideally I would like to be able to do something like this:

test_class = Test()
print "Hey {0.hey}, let's {1.yo}. Fo' {2.sho}".format(test_class)

But I have to do this:

test_class = Test()
print "Hey {0.hey}, let's {1.yo}. Fo' {2.sho}".format(test_class, test_class, test_class)
Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
Peter Featherstone
  • 7,835
  • 4
  • 32
  • 64

6 Answers6

6

As you found out for yourself, you can use keyword arguments, but you don't even have to do that:

In [4]: print("Hey {0.hey}, let's {0.yo}. Fo' {0.fo}".format(t))
Hey ho, let's go. Fo' sho

In [5]: class Test:
   ...:     hey = 'ho'
   ...:     yo = 'go'
   ...:     fo = 'sho'
   ...:

In [6]: t = Test()

In [7]: print("Hey {0.hey}, let's {0.yo}. Fo' {0.fo}".format(t))
Hey ho, let's go. Fo' sho

The 0 refers to the zeroth argument to format, the problem was you had no 1st and second argument, because you didn't need it.

Warning as an aside:

Also, since you seem to be coming to python from other languages, you might be making a common mistake. Note that the way you have defined your class;

class Test:
    hey = 'ho'
    yo = 'go'
    fo = 'sho'

uses only class-level variables, which will act like static members to borrow terminology from other languages. In other words, hey, yo, and fo are not instance attributes, although your instances have access to the class-level namespace. Check out this answer. Of course, this doesn't matter for the purposes of this question, but it can lead to bugs if you don't understand the semantics of the class definition.

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
  • 1
    Thanks for the thorough answer @juanpa.arrivillaga. I have been caught out by class level variables before but this was more a question of formatting than the class semantics themselves, but thanks for the insight - always nice to get a reminder! – Peter Featherstone Aug 04 '17 at 17:57
4

As soon as I posted this I realised I could just keyword arguments.

test_class = Test()
print "Hey {my_class.hey}, let's {my_class.yo}. Fo' {my_class.sho}".format(my_class=test_class)

In addition, as per my original question this is possible by just reusing the 0 positional argument as below:

test_class = Test()
print "Hey {0.hey}, let's {0.yo}. Fo' {0.sho}".format(test_class)

Also, as pointed out by Ryan in the comments Python 3.6+ comes with the new f-string, which means I could also do this:

test_class = Test()
print(f"Hey {test_class.hey}, let's {test_class.yo}. Fo' {test_class.sho}")
Peter Featherstone
  • 7,835
  • 4
  • 32
  • 64
2

{0.hey} is referring to the 'hey' attribute of the first argument passed to format.

So you just have to refer to the correct argument:

test_class = Test()
print "Hey {0.hey}, let's {0.yo}. Fo' {0.fo}".format(test_class)
Nicolas Appriou
  • 2,208
  • 19
  • 32
2

Just for posterity, as said in the comments, anyone using Python 3.6 and greater can make use of the new format string literals specified in PEP 498:

class Test:
    hey = 'ho'
    yo = 'go'
    fo = 'sho'

test = Test()
print(f"Hey {test.hey}, let's {test.yo}. Fo' {test.fo}")
# Hey ho, let's go. Fo' sho

More format strings(f-strings for short) can be found in the Formatted string literals section of Python documentation.

Christian Dean
  • 22,138
  • 7
  • 54
  • 87
1

If you change 1 and 2 by 0 you reuse the same argument and format does what you want.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
1

Can also use a dict to pass values:

dict_ = {
    "hey": 'ho',
    "yo":'go',
    "fo":'sho'
    }

print("Hey {0[hey]}, let's {0[yo]}. Fo' {0[fo]}".format(dict_))

Or an ordered dict:

from collections import OrderedDict

dict_ = OrderedDict([('hey','ho'),('yo','go'),('fo','sho')])

print("Hey {}, let's {}. Fo' {}".format(*dict_.values()))
print("Hey {0}, let's {1}. Fo' {2}".format(*dict_.values()))
Anton vBR
  • 18,287
  • 5
  • 40
  • 46