i'm trying to do some "post"/"lazy" evaluation of arguments on my strings. Suppose i've this:
我正在尝试对我的字符串上的参数进行一些“post”/“lazy”评估。假设我是这样的:
s = "SELECT * FROM {table_name} WHERE {condition}"
I'd like to return the string with the {table_name}
replaced, but not the {condition}
, so, something like this:
我想返回替换{table_name}的字符串,而不是{condition},所以,像这样:
s1 = s.format(table_name = "users")
So, I can build the hole string later, like:
所以,我可以在以后构建孔字符串,如:
final = s1.format(condition= "user.id = {id}".format(id=2))
The result should be, of course:
结果当然应该是:
"SELECT * FROM users WHERE user.id = 2"
I've found this previous answer, this is exactly what I need, but i'd like to use the format
string function.
我已经找到了之前的答案,这正是我需要的,但我想使用格式字符串函数。
python, format string Thank you for your help!
python,格式字符串谢谢你的帮助!
6 个解决方案
#1
6
You can't use the format function because it will raise a KeyError.
您不能使用format函数,因为它会引发KeyError。
string.Template
supports safe substituion:
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'
If you use plain variable names (no format specifiers, no indexing, etc..) this will also work (thanks @Simeon Visser for the idea):
如果您使用普通变量名称(没有格式说明符,没有索引等等),这也将起作用(感谢@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
7
You can replace the condition with itself:
您可以用自己替换条件:
s.format(table_name='users', condition='{condition}')
which gives us:
这给了我们:
SELECT * FROM users WHERE {condition}
You can use this string later to fill in the condition.
您可以稍后使用此字符串填写条件。
#3
1
This builds on @Karoly Horvath's answer to add support for index keys and attribute access on named keys:
这建立在@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
So to test it out:
所以要测试一下:
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)
Output:
输出:
{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}
#4
1
I have been using this function for some time now, which casts the Dict
of inputted keyword arguments as a SafeDict
object that subclasses Dict
.
我一直在使用这个函数,它将输入的关键字参数的Dict转换为子类Dict的SafeDict对象。
def safeformat(str, **kwargs):
class SafeDict(dict):
def __missing__(self, key):
return '{' + key + '}'
replacements = SafeDict(**kwargs)
return str.format_map(replacements)
I didn't make this up, but I think it's a good solution. The one downside is that you can't call mystring.safeformat(**kwargs)
- of course, you have to call safeformat(mystring,**kwargs)
.
我没有提出这个问题,但我认为这是一个很好的解决方案。一个缺点是你不能调用mystring.safeformat(** kwargs) - 当然,你必须调用safeformat(mystring,** kwargs)。
If you're really interested in being able to call mystr.safeformat(**kwargs)
(which I am interested in doing!), consider using this:
如果你真的有兴趣能够调用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))
You can then create a safestr
object as a = safestr(mystr)
(for some str
called mystr
), and you can in fact call mystr.safeformat(**kwargs)
.
然后你可以创建一个safestr对象作为a = safestr(mystr)(对于一些名为mystr的str),你实际上可以调用mystr.safeformat(** kwargs)。
e.g.
例如
mysafestr = safestr('Hey, {friendname}. I am {myname}.')
print(mysafestr.safeformat(friendname='Bill'))
prints
版画
Hey, Bill. I am {myname}.
嘿,比尔。我是{myname}。
This is cool in some ways - you can pass around a partially-formatted safestr
, and could call safeformat
in different contexts. I especially like to call mystr.format(**locals())
to format with the appropriate namespace variables; the safeformat
method is especially useful in this case, because I don't always carefully looks through my namespace.
这在某些方面很酷 - 您可以传递部分格式化的safestr,并可以在不同的上下文中调用safeformat。我特别喜欢调用mystr.format(** locals())来使用适当的命名空间变量进行格式化;在这种情况下,safeformat方法特别有用,因为我并不总是仔细查看我的命名空间。
The main issue with this is that inherited methods from str
return a str
object, not a safestr
. So mysafestr.lower().safeformat(**kwargs)
fails. Of course you could cast as a safestr
when using safeformat
:
这个问题的主要问题是str的继承方法返回一个str对象,而不是一个safestr。所以mysafestr.lower()。safeformat(** kwargs)失败了。当然,使用safeformat时可以将其作为safestr进行转换:
safestr(mysafestr.lower()).safeformat(**kwargs)
,
safestr(mysafestr.lower())。safeformat(** kwargs),
but that's less than ideal looking. I wish Python just gave the str
class a safeformat
method of some kind.
但那看起来并不理想。我希望Python只给str类一个安全格式的方法。
#5
0
This is a slight change to @ShawnFumo's answer which has a small bug. We need to add a word boundary check (the \b in the regular expression) to ensure that we are matching only the failing key and another key that starts with the same string. This prevents a missing {foo} key from also treating {food} and {foolish} as if they were missing.
这是对@ 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
So to test it out:
所以要测试一下:
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')
Output:
输出:
{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
#6
0
An alternative to string.Template.safe_substitute
could be subclassing string.Formatter
like so:
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'})
Output:
输出:
foo: {value}
#1
6
You can't use the format function because it will raise a KeyError.
您不能使用format函数,因为它会引发KeyError。
string.Template
supports safe substituion:
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'
If you use plain variable names (no format specifiers, no indexing, etc..) this will also work (thanks @Simeon Visser for the idea):
如果您使用普通变量名称(没有格式说明符,没有索引等等),这也将起作用(感谢@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
7
You can replace the condition with itself:
您可以用自己替换条件:
s.format(table_name='users', condition='{condition}')
which gives us:
这给了我们:
SELECT * FROM users WHERE {condition}
You can use this string later to fill in the condition.
您可以稍后使用此字符串填写条件。
#3
1
This builds on @Karoly Horvath's answer to add support for index keys and attribute access on named keys:
这建立在@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
So to test it out:
所以要测试一下:
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)
Output:
输出:
{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}
#4
1
I have been using this function for some time now, which casts the Dict
of inputted keyword arguments as a SafeDict
object that subclasses Dict
.
我一直在使用这个函数,它将输入的关键字参数的Dict转换为子类Dict的SafeDict对象。
def safeformat(str, **kwargs):
class SafeDict(dict):
def __missing__(self, key):
return '{' + key + '}'
replacements = SafeDict(**kwargs)
return str.format_map(replacements)
I didn't make this up, but I think it's a good solution. The one downside is that you can't call mystring.safeformat(**kwargs)
- of course, you have to call safeformat(mystring,**kwargs)
.
我没有提出这个问题,但我认为这是一个很好的解决方案。一个缺点是你不能调用mystring.safeformat(** kwargs) - 当然,你必须调用safeformat(mystring,** kwargs)。
If you're really interested in being able to call mystr.safeformat(**kwargs)
(which I am interested in doing!), consider using this:
如果你真的有兴趣能够调用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))
You can then create a safestr
object as a = safestr(mystr)
(for some str
called mystr
), and you can in fact call mystr.safeformat(**kwargs)
.
然后你可以创建一个safestr对象作为a = safestr(mystr)(对于一些名为mystr的str),你实际上可以调用mystr.safeformat(** kwargs)。
e.g.
例如
mysafestr = safestr('Hey, {friendname}. I am {myname}.')
print(mysafestr.safeformat(friendname='Bill'))
prints
版画
Hey, Bill. I am {myname}.
嘿,比尔。我是{myname}。
This is cool in some ways - you can pass around a partially-formatted safestr
, and could call safeformat
in different contexts. I especially like to call mystr.format(**locals())
to format with the appropriate namespace variables; the safeformat
method is especially useful in this case, because I don't always carefully looks through my namespace.
这在某些方面很酷 - 您可以传递部分格式化的safestr,并可以在不同的上下文中调用safeformat。我特别喜欢调用mystr.format(** locals())来使用适当的命名空间变量进行格式化;在这种情况下,safeformat方法特别有用,因为我并不总是仔细查看我的命名空间。
The main issue with this is that inherited methods from str
return a str
object, not a safestr
. So mysafestr.lower().safeformat(**kwargs)
fails. Of course you could cast as a safestr
when using safeformat
:
这个问题的主要问题是str的继承方法返回一个str对象,而不是一个safestr。所以mysafestr.lower()。safeformat(** kwargs)失败了。当然,使用safeformat时可以将其作为safestr进行转换:
safestr(mysafestr.lower()).safeformat(**kwargs)
,
safestr(mysafestr.lower())。safeformat(** kwargs),
but that's less than ideal looking. I wish Python just gave the str
class a safeformat
method of some kind.
但那看起来并不理想。我希望Python只给str类一个安全格式的方法。
#5
0
This is a slight change to @ShawnFumo's answer which has a small bug. We need to add a word boundary check (the \b in the regular expression) to ensure that we are matching only the failing key and another key that starts with the same string. This prevents a missing {foo} key from also treating {food} and {foolish} as if they were missing.
这是对@ 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
So to test it out:
所以要测试一下:
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')
Output:
输出:
{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
#6
0
An alternative to string.Template.safe_substitute
could be subclassing string.Formatter
like so:
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'})
Output:
输出:
foo: {value}