python-字符串模板-相同键的不同值

python-字符串模板-相同键的不同值,python,template-engine,Python,Template Engine,我有一个SQL模板,需要在其中替换随机UUID from string import Template import uuid def gen_uuid(): return str(uuid.uuid4()) s = """ insert ... values('foo', ${uuid}); insert ... values('bar', ${uuid}); insert ... values('baz', ${uuid}); """ mappings = { "uui

我有一个SQL模板,需要在其中替换随机UUID

from string import Template
import uuid

def gen_uuid():
    return str(uuid.uuid4())

s = """
insert ... values('foo', ${uuid});
insert ... values('bar', ${uuid});
insert ... values('baz', ${uuid});
"""

mappings = {
    "uuid": gen_uuid  # how??
}

template = Template(s)
print template.safe_substitute(mappings)
如何将不同的UUID值绑定到同一模板键

更新

好的。。我最终覆盖了
getitem
。不是很理想,但很管用

class UUIDDict(dict):
    def __init__(self, *args, **kwargs):
        self.update(*args, **kwargs)

    def __getitem__(self, key):
        if key == 'uuid':
            return str(uuid.uuid4())

        return super(UUIDDict, self).__getitem__(key)

第一个问题是您没有将gen_uuid的结果传递给模板,而是引用了函数对象本身。应该是:

mappings = {
    "uuid": gen_uuid()
}
使用当前方法,gen_uuid函数只计算一次,因此每个语句将使用相同的值

为什么不这样做呢

names = ['foo', 'bar', 'baz']

for name in names:
    c.execute("INSERT into foo (a, b) VALUES (%s, %s)", (name, gen_uuid()))
不是为用多个值替换单个键而设计的。其他模板系统可能支持这一点,但string.Template应该非常简单

也就是说,在循环中执行您想要的操作,然后使用str.join组合结果并不困难:

正如OP所建议的,可以创建一个自定义字典,该字典将在每次查找时构建一个新的uuid():

>>> class UUID_Dict(dict):
        def __missing__(self, key):
            if key == 'uuid':
                 return str(uuid.uuid4())
            raise KeyError(key)


>>> s = Template("""
insert ... values('foo', ${uuid});
insert ... values('bar', ${uuid});
insert ... values('baz', ${uuid});
""")
>>> print s.substitute(UUID_Dict())

insert ... values('foo', eabc65b6-1294-43b7-9506-61a4e324e0f2);
insert ... values('bar', 93e4f0b7-7fa1-4e88-9696-e361da31358f);
insert ... values('baz', 503d34a3-17a4-4513-8ce0-b5efb70c94cc);

下面是一个使用“默认字典”(defaultdictionary)的解决方案(
defaultdict
):

结果如下所示:

insert ... values('foo', aedd5fb6-40da-45bd-bcf7-c7390ef8f13e);
insert ... values('bar', c7ea3090-2a0f-49aa-ace9-c5ef67b7888b);
insert ... values('baz', bf2d86b7-c13e-4498-8d4a-27e76c2e72ab);
一个
defaultdict
是用一个参数,一个工厂函数创建的。每次在默认字典中查找未知键时,它都会调用该函数,将该值绑定到该键,然后返回该键。因此,它将为每个变量分配一个新的UUID

主要缺点是不能使用单个变量
${uuid}
;您必须为每个uuid定义一个新变量。而且,从长远来看,这可能是更好的做法:这样,如果您再次需要,您可以访问模板中每个值的特定UUID。在完成模板替换后,您甚至可以直接从Python代码访问UUID:

>>> for k, v in mappings.items():
...     print k, v
... 
baz_uuid bf2d86b7-c13e-4498-8d4a-27e76c2e72ab
bar_uuid c7ea3090-2a0f-49aa-ace9-c5ef67b7888b
foo_uuid aedd5fb6-40da-45bd-bcf7-c7390ef8f13e

这会为键分配一个特定的UUID值,因此我会为所有行获得相同的UUID。您没有回答这个问题。OP希望在不同的位置用不同的值替换相同的模板键。您的解决方案将用
gen_uuid()
(一个,相同的结果)的结果替换所有的字符串。您知道字符串模板是否在每次遇到键时都进行查找吗?在这种情况下,我可以重写字典,为['uuid']返回不同的值。这是一种黑客行为。@armandino是的,那会有用的。我编辑了答案以展示如何:-)谢谢雷蒙德!我应该提到,insert语句并不总是相同的。。我只是不想把这个例子复杂化。
insert ... values('foo', aedd5fb6-40da-45bd-bcf7-c7390ef8f13e);
insert ... values('bar', c7ea3090-2a0f-49aa-ace9-c5ef67b7888b);
insert ... values('baz', bf2d86b7-c13e-4498-8d4a-27e76c2e72ab);
>>> for k, v in mappings.items():
...     print k, v
... 
baz_uuid bf2d86b7-c13e-4498-8d4a-27e76c2e72ab
bar_uuid c7ea3090-2a0f-49aa-ace9-c5ef67b7888b
foo_uuid aedd5fb6-40da-45bd-bcf7-c7390ef8f13e