8

Someone has recently demonstrated to me that we can print variables in Python like how Perl does.

Instead of:

print("%s, %s, %s" % (foo, bar, baz))

we could do:

print("%(foo)s, %(bar)s, %(baz)s" % locals())

Is there a less hacky looking way of printing variables in Python like we do in Perl? I think the 2nd solution actually looks really good and makes code a lot more readable, but the locals() hanging around there makes it look like such a convoluted way of doing it.

Axeman
  • 29,660
  • 2
  • 47
  • 102
Ish
  • 145
  • 5
  • This looks awfully close to http://stackoverflow.com/questions/3534714/python-equivalent-to-perls-qw ... – David Z Aug 20 '10 at 20:50
  • 1
    http://stackoverflow.com/questions/1550479 (no endorsement of the answers, which I havn't read) – Glenn Maynard Aug 20 '10 at 20:59
  • 1
    You've said, essentially, that you want Python to be more like Perl. Which aspect of Perl? There's more than one way to format a string. – Greg Hewgill Aug 20 '10 at 21:16
  • 1
    Just the part where we can format a string by referencing variables directly in the quotes, rather than having to format it outside of the quotes. I just find that strings are a lot more readable when you don't have to read outside the quotes. No break in flow (can't think of a better way to describe it.. urgh) – Ish Aug 20 '10 at 21:32
  • @Greg: What are you talking about? He said exactly what he wants. – Glenn Maynard Aug 20 '10 at 21:39
  • @Glenn Maynard: Perl has at least: (a) sprintf, (b) string interpolation, and (c) concatenation. I didn't think it was obvious at first glance which one Chien is looking for. A Perl example would have made it completely clear. – Greg Hewgill Aug 20 '10 at 21:55
  • @Greg: Seems clear enough: using `"%(foo)s, %(bar)s, %(baz)s"` like `"$foo, $bar, $baz`. *shrug* – Glenn Maynard Aug 20 '10 at 22:45
  • @Chien: When you want to print variables it's time to start a debugger. PyDev has one *everyone* can use right away. – Jochen Ritzel Aug 21 '10 at 00:03
  • See also: http://stackoverflow.com/q/15013982/490829 (shameless promotion) – forivall Feb 21 '13 at 23:39
  • I'm endorsing the great answer http://stackoverflow.com/questions/1550479/python-is-using-vars-locals-a-good-practice/1551187#1551187 for why this is a bad idea. Quoting the Zen of Python: `Explicit is better than implicit.` /cc @GlennMaynard – clacke Mar 12 '15 at 14:19

5 Answers5

10

The only other way would be to use the Python 2.6+/3.x .format() method for string formatting:

# dict must be passed by reference to .format()
print("{foo}, {bar}, {baz}").format(**locals()) 

Or referencing specific variables by name:

# Python 2.6
print("{0}, {1}, {2}").format(foo, bar, baz) 

# Python 2.7/3.1+
print("{}, {}, {}").format(foo, bar, baz)    
jathanism
  • 33,067
  • 9
  • 68
  • 86
  • This doesn't exactly make it look cleaner. – Glenn Maynard Aug 20 '10 at 21:04
  • 1
    Just added the specific ones for when referencing the variable directly. The 2.7/3.1+ version is definitely the cleanest of them all in my opinion. – jathanism Aug 20 '10 at 21:11
  • 3
    Fine, right up until you start pulling the strings from a localization database. At that point, you have to go back to using explicit orderings because different languages prefer different orders of values. (Really.) – Donal Fellows Aug 20 '10 at 21:33
  • 2
    you can use `vars()` instead of `locals()`. Also `vars(obj)` to use `obj.__dict__` for the substitutions – John La Rooy Aug 21 '10 at 07:10
5

Using % locals() or .format(**locals()) is not always a good idea. As example, it could be a possible security risk if the string is pulled from a localization database or could contain user input, and it mixes program logic and translation, as you will have to take care of the strings used in the program.

A good workaround is to limit the strings available. As example, I have a program that keeps some informations about a file. All data entities have a dictionary like this one:

myfile.info = {'name': "My Verbose File Name", 
               'source': "My Verbose File Source" }

Then, when the files are processes, I can do something like this:

for current_file in files:
    print 'Processing "{name}" (from: {source}) ...'.format(**currentfile.info)
    # ...
leoluk
  • 12,561
  • 6
  • 44
  • 51
  • +1 This is a good point. Don't know why someone would downvote it. – John La Rooy Aug 21 '10 at 06:55
  • Yep, see http://stackoverflow.com/questions/1550479/python-is-using-vars-locals-a-good-practice/1551187#1551187 for a thorough discussion on why `Explicit is better than implicit.` in exactly this context. – clacke Mar 12 '15 at 14:21
3

I prefer the .format() method myself, but you can always do:

age = 99
name = "bobby"
print name, "is", age, "years old"

Produces: bobby is 99 years old. Notice the implicit spaces.

Or, you can get real nasty:

def p(*args):
    print "".join(str(x) for x in args))

p(name, " is ", age, " years old")
carl
  • 49,756
  • 17
  • 74
  • 82
2

Since Python 3.6, you could have what you wanted.

>>> name = "world"
>>> print(f'hello {name}')
hello world

note the string prefix f above

Mike Pennington
  • 41,899
  • 19
  • 136
  • 174
ospider
  • 9,334
  • 3
  • 46
  • 46
1

The answer is, no, the syntax for strings in Python does not include variable substitution inthe style of Perl (or Ruby, for that matter). Using … % locals() is about as slick as you are going to get.

pdc
  • 2,314
  • 20
  • 28