Mark Damon Hughes Python string formatting [Parental Advisory: Explicit Lyrics] [about]
Python string formatting
Wed, 2010Aug25 22:47:01 PDT
in Software by kamikaze

Python's string formatting tools annoy me. And what annoys me, eventually gets fixed, even if it's with an evil hack.


In Perl (and originally in Bourne Shell), you can write:

print "It is ${foo}!";
to show the value of local variable foo. Simple, clear, and terse.

In Python up to 2.4, you would write:

print "It is %s!" % (foo,)
But that makes you match up positional arguments, which sucks. So there's this:
print "It is %(foo)s!" % {"foo":foo}

In Python 2.5 and later, there's a new formatter:

print "It is {foo}!".format(foo=foo)

In Python 3.0 and later, it's now:

print("It is {foo}!".format(foo=foo))
There's also Template, but it's even longer and uglier.

This is a mess. You can't even find the message in all that line noise, and the name is repeated 2 extra times. Printing several values is unmaintainable.

Hack #1: Use vars() to hide the redundant name assignment.

print("It is {foo}!".format(**vars()))
# **aDict expands the dict as keyword args
Or:
print("It is %(foo)s!" % vars())

Still a lot of noise, but foo is just pulled from local scope. Maybe I can hide that vars() assignment?

Hack #2:

print(fmt("It is {foo}!"))

Sweet! How did I do that? It is magic! But it's black, vile, corrupt magic, and it's about 120x slower than the ugly one (though still unnoticeably fast on modern hardware).

""">>>import inspect
>>>x=2
>>>fmt("{0} {x} {y}", 1, y=3)
'1 2 3'
"""
def fmt(s, *args, **kwargs):
	c_frame = inspect.getouterframes(inspect.currentframe(), 1)[1][0]
	c_args, c_varargs, c_varkw, c_locals = inspect.getargvalues(c_frame)
	d = dict(c_locals)
	if kwargs: d.update(kwargs)
	return s.format(*args, **d)
← Previous: "I am the death of e-ink", said the iPad. (Toys) Next: The iPod nano watch (Mac) →
Feedback  | Key: ] =local file, * =off-site link  | Copyright © 2003-2010 by Mark Damon Hughes | Subscribe with RSS 2.0