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

发布于 2024-12-18 05:41:18 字数 761 浏览 2 评论 0原文

我有一个 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)

I have an SQL template where I need to substitute random UUIDs.

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?

Update

Ok.. I ended up overriding 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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

地狱即天堂 2024-12-25 05:41:18

string.Template() 并非旨在用多个值替换单键。其他模板系统可能支持这一点,但 string.Template 本来就很简单。

话虽这么说,在循环中执行您想要的操作,然后使用 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);

根据 OP 的建议,可以创建一个自定义字典来构建一个每次查找时使用 new 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);

string.Template() isn't designed to substitute multiple values for a single key. Other templating systems may support this, but string.Template is meant to be dirt simple.

That being said, it isn't hard to do what you want in a loop and then combine the results using 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:

>>> 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);
莫言歌 2024-12-25 05:41:18

第一个问题是您没有将 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()))

The first problem is you're not passing the result of gen_uuid to the template, you're referencing the function object itself. 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.

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()))
层林尽染 2024-12-25 05:41:18

这是使用“默认字典”(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)

结果将类似于以下内容:

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

Here is a solution that uses a "default dictionary" (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. 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.

The main disadvantage is that you can't use the single variable ${uuid}; You will have to define a new variable for each 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. You could even access the UUIDs direct from the Python code, after you do the template substitution:

>>> 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文