我正在尝试对我的字符串上的参数进行一些“post”/“lazy”评估。假设我是这样的:
s = "SELECT * FROM {table_name} WHERE {condition}"
我想要更换{table_name}
替换的字符串,而不是{condition}
,这样的话就像这样:
s1 = s.format(table_name = "users")
所以,我可以在以后构建孔字符串,例如:
final = s1.format(condition= "user.id = {id}".format(id=2))
结果当然应该是:
"SELECT * FROM users WHERE user.id = 2"
我已经找到了之前的答案,这正是我需要的,但我想使用format
字符串函数。
python, format string 谢谢你的帮助!
答案 0 :(得分:7)
您可以用自己替换条件:
s.format(table_name='users', condition='{condition}')
给了我们:
SELECT * FROM users WHERE {condition}
您可以稍后使用此字符串填写条件。
答案 1 :(得分:6)
您不能使用format函数,因为它会引发KeyError。
string.Template
支持安全替代:
from string import Template
s = Template('SELECT * FROM $table_name WHERE $condition')
s.safe_substitute(table_name='users')
'SELECT * FROM users WHERE $condition'
如果您使用普通变量名称(没有格式说明符,没有索引等等),这也会有效(感谢@Simeon Visser的想法):
def myformat(s, *args, **kwargs):
while True:
try:
return s.format(*args, **kwargs)
except KeyError as e:
e=e.args[0]
kwargs[e] = "{%s}" % e
s = "SELECT * FROM {table_name} WHERE {condition}"
myformat(s, table_name="users")
'SELECT * FROM users WHERE {condition}'
答案 2 :(得分:1)
这建立在@Karoly Horvath的答案之上,以增加对指定键的索引键和属性访问的支持:
import re
def my_format(template, *args, **kwargs):
next_index = len(args)
while True:
try:
return template.format(*args, **kwargs)
except KeyError as e:
key = e.args[0]
finder = '\{' + key + '.*?\}'
template = re.sub(finder, '{\g<0>}', template)
except IndexError as e:
args = args + ('{' + str(next_index) + '}',)
next_index += 1
所以要测试一下:
class MyObj:
bar = 'baz'
def __repr__(self):
return '<MyObj instance>'
my_obj = MyObj()
template = '{0}, {1}, {foo}, {foo.bar}, {0}, {10}, {missing}'
print my_format(template)
print my_format(template, '1st', '2nd', missing='Not Missing')
print my_format(template, foo=my_obj)
输出:
{0}, {1}, {foo}, {foo.bar}, {0}, {10}, {missing}
1st, 2nd, {foo}, {foo.bar}, 1st, {10}, Not Missing
{0}, {1}, <MyObj instance>, baz, {0}, {10}, {missing}
答案 3 :(得分:1)
我一直在使用这个函数一段时间,它将Dict
输入的关键字参数转换为SafeDict
子类Dict
的对象。
def safeformat(str, **kwargs):
class SafeDict(dict):
def __missing__(self, key):
return '{' + key + '}'
replacements = SafeDict(**kwargs)
return str.format_map(replacements)
我没有做到这一点,但我认为这是一个很好的解决方案。一个缺点是您无法拨打mystring.safeformat(**kwargs)
- 当然,您必须致电safeformat(mystring,**kwargs)
。
如果你真的有兴趣打电话给mystr.safeformat(**kwargs)
(我有兴趣做的话!),请考虑使用:
class safestr(str):
def safeformat(self, **kwargs):
class SafeDict(dict):
def __missing__(self, key):
return '{' + key + '}'
replacements = SafeDict(**kwargs)
return safestr(self.format_map(replacements))
然后,您可以将safestr
对象创建为a = safestr(mystr)
(对于名为str
的某些mystr
,您实际上可以调用
mystr.safeformat(**kwargs)
。
e.g。
mysafestr = safestr('Hey, {friendname}. I am {myname}.')
print(mysafestr.safeformat(friendname='Bill'))
打印
Hey, Bill. I am {myname}.
这在某些方面很酷 - 您可以传递部分格式化的safestr
,并可以在不同的上下文中调用safeformat
。我特别喜欢调用mystr.format(**locals())
来使用适当的命名空间变量进行格式化;在这种情况下,safeformat
方法特别有用,因为我并不总是仔细查看我的命名空间。
这个问题的主要问题是来自str
的继承方法会返回str
个对象,而不是safestr
。所以mysafestr.lower().safeformat(**kwargs)
失败了。当然,使用safestr
时,您可以投放safeformat
:
safestr(mysafestr.lower()).safeformat(**kwargs)
,
但这看起来并不理想。我希望Python只为str
类提供某种safeformat
方法。
答案 4 :(得分:0)
这是对@ ShawnFumo的答案的一个小改动,它有一个小错误。我们需要添加一个单词边界检查(正则表达式中的\ b),以确保我们只匹配失败的密钥和另一个以相同字符串开头的密钥。这可以防止丢失的{foo}键同时处理{food}和{foolish},就像它们丢失一样。
import re
def my_format(template, *args, **kwargs):
next_index = len(args)
while True:
try:
return template.format(*args, **kwargs)
except KeyError as e:
key = e.args[0]
finder = r'\{' + key + r'\b.*?\}'
template = re.sub(finder, r'{\g<0>}', template)
except IndexError as e:
args = args + ('{' + str(next_index) + '}',)
next_index += 1
所以要测试一下:
class MyObj:
bar = 'baz'
def __repr__(self):
return '<MyObj instance>'
my_obj = MyObj()
template = '{0}, {1}, {foo}, {foo.bar}, {0}, {10}, {missing}'
print my_format(template)
print my_format(template, '1st', '2nd', missing='Not Missing')
print my_format(template, foo=my_obj)
print
template2 = '{foo} and {food}'
print my_format(template2)
print my_format(template2, food='burger')
print my_format(template2, foo=my_obj, food='burger')
输出:
{0}, {1}, {foo}, {foo.bar}, {0}, {10}, {missing}
1st, 2nd, {foo}, {foo.bar}, 1st, {10}, Not Missing
{0}, {1}, <MyObj instance>, baz, {0}, {10}, {missing}
{foo} and {food}
{foo} and burger
repr(<MyObj instance>) and burger
答案 5 :(得分:0)
string.Template.safe_substitute
的替代方法可以像这样继承string.Formatter
:
class LazyFormatter(string.Formatter):
def get_value(self, key, args, kwargs):
'''Overrides string.Formatter.get_value'''
if isinstance(key, (int, long)):
return args[key]
else:
return kwargs.get(key, '{{{0}}}'.format(key))
lazyfmt = LazyFormatter()
print lazyfmt.format("{field}: {value}", **{'field': 'foo'})
输出:
foo: {value}