简体   繁体   English

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

[英]python - string template - different values for same key

I have an SQL template where I need to substitute random UUIDs. 我有一个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)

How can I bind different UUIDs values to the same template key? 如何将不同的UUID值绑定到同一模板键?

Update 更新

Ok.. I ended up overriding getitem . 好的..我最终重载了getitem Not ideal but works.. 不理想,但工作..

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)

The first problem is you're not passing the result of gen_uuid to the template, you're referencing the function object itself. 第一个问题是您没有将gen_uuid的结果传递给模板,而是在引用函数对象本身。 It should be: 它应该是:

mappings = {
    "uuid": gen_uuid()
}

With your current approach the gen_uuid function will only be evaluated once, so the same value will be used for each statement. 使用当前的方法,gen_uuid函数将仅被评估一次,因此每个语句将使用相同的值。

Why not do something like this instead?: 为什么不做这样的事呢?:

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

for name in names:
    c.execute("INSERT into foo (a, b) VALUES (%s, %s)", (name, gen_uuid()))

string.Template() isn't designed to substitute multiple values for a single key. string.Template()不是为单个键替换多个值。 Other templating systems may support this, but string.Template is meant to be dirt simple. 其他模板系统可能会支持这一点,但string.Template意味着很简单。

That being said, it isn't hard to do what you want in a loop and then combine the results using str.join : 话虽如此,在循环中执行您想要的操作并不难,然后使用str.join组合结果:

>>> from string import Template
>>> import uuid
>>> def gen_uuid():
        return str(uuid.uuid4())

>>> s = Template("insert ... values('$name', ${uuid});")
>>> t = [s.substitute(name=name, uuid=gen_uuid()) for name in ('foo', 'bar', 'baz')]
>>> print '\n'.join(t)
insert ... values('foo', ee1b1b21-c022-4de5-8f7c-0a4d0554ae49);
insert ... values('bar', 0b96872f-ab0e-48cf-a025-f997f7976a0e);
insert ... values('baz', 25165bb6-8b7b-4c87-9ce1-ca274fc51bc8);

As suggested by the OP, a custom dictionary can be created that will build a new uuid() on each lookup: 根据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);

Here is a solution that uses a "default dictionary" ( defaultdict ): 这是使用“默认字典”( defaultdict )的解决方案:

from collections import defaultdict
from string import Template
import uuid

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

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

mappings = defaultdict(gen_uid)
template = Template(s)
print template.safe_substitute(mappings)

The result will be something like the following: 结果将如下所示:

insert ... values('foo', aedd5fb6-40da-45bd-bcf7-c7390ef8f13e);
insert ... values('bar', c7ea3090-2a0f-49aa-ace9-c5ef67b7888b);
insert ... values('baz', bf2d86b7-c13e-4498-8d4a-27e76c2e72ab);

A defaultdict is created with a single argument, a factory function. defaultdict是使用单个参数(工厂函数)创建的。 Every time an unknown key is looked up in a default dictionary, it calls that function, binds that value to the key, and then returns the key. 每次在默认字典中查找未知键时,它都会调用该函数,将该值绑定到该键,然后返回该键。 Thus it will assign a new UUID to each variable. 因此,它将为每个变量分配一个新的UUID。

The main disadvantage is that you can't use the single variable ${uuid} ; 主要的缺点是你不能使用单变量${uuid} ; You will have to define a new variable for each uuid. 您将必须为每个uuid定义一个新变量。 Then again, this may be better practice in the long run: that way, you can access the particular UUID for each value in the template should you need it again. 然后,从长远来看,这可能是更好的做法:这样,如果您再次需要,您可以访问模板中每个值的特定UUID。 You could even access the UUIDs direct from the Python code, after you do the template substitution: 进行模板替换后,您甚至可以直接从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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM