Reputation: 420
I'm considering porting a rather unwieldy bash script to python but I'm stuck on how to handle the following aspect: The point of the script is to generate a png image depending on dynamically fetched data. The bash script grabs the data, and builds a very long invocation of the convert
utility, with lots of options. It seemed like python's template strings would be a good solution (I would vastly prefer to stay within the standard library, since I'll be deploying to shared hosting), but I discovered that you can't evaluate expressions as you can in bash:
>>> from string import Template
>>> s = Template('The width times one is ${width}')
>>> s.substitute(width=45)
'The width times one is 45'
>>> t = Template('The width times two is ${width*2}')
>>> t.substitute(width=45)
# Raises ValueError
Since my bash script depends quite heavily on such arithmetic (otherwise the number of variables to keep track of would increase exponentially) I'd like to know if there's a way to emulate this behavior in python. I saw that this question, asking roughly the same, has a comment, reading:
This would be very unPythonic, because it's counterintuitive -- strings are just strings, they shouldn't run code!
If this is the case, what would be a more idiomatic way to approach this problem?
The proposed answer to the question linked above is to use string formatting with either the %
syntax or the format()
function, but I don't think that would work well with the number of variables in my string (around 50).
Upvotes: 2
Views: 2166
Reputation: 571
The task is not that hard, why don't you just make some coding for fun? And here is the function almost does what you want.
import re
def TempEval(template,**kwargs):
mark = re.compile('\${(.*?)}')
for key in kwargs:
exec('%s=%s'%(key,kwargs[key]))
for item in mark.findall(template):
template=template.replace('${%s}'%item,str(eval(item)))
return template
print TempEval('The width times one is ${width}',width=5)
#The width times one is 5
print TempEval('The width times two is ${width*2}',width=5)
#The width times two is 10
Upvotes: 2
Reputation: 95298
You probably need a better templating engine. Jinja2
supports this kind of stuff and a lot more. I don't think the standard library has anything equally powerful, but from what I figured, the library is pure Python, so you can integrate it into your application by just copying it along.
If Jinja doesn't fit you for some reason, have a look at the Python wiki, which has a section specifically for those kinds of libraries. Amongst them is the very lightweight Templite, which is only one class and seems to do exactly what you need.
Upvotes: 2
Reputation: 363547
The Pythonic solution to this problem is to forget about string formatting and pass a list of arguments to one of the subprocess
functions, e.g.
# I have no idea about convert's command line usage,
# so here's an example using echo.
subprocess.call(["echo", str(1 + 1), "bla"])
That way, there's no need to build a single string and no need to worry about quoting.
Upvotes: 2
Reputation: 56634
Why not use built-in string formatting?
width = 45
"Width times one is {width}".format(width=width)
"Width times two is {width}".format(width=2*width)
results in
Width times one is 45
Width times two is 90
Upvotes: 3