Python 中的嵌套 f 字符串(第三个嵌套 f 字符串)

Nested f-strings in Python (Third nested f-string)

我需要将 json 转换为给定的 hcl 结构。有这个代码:

user_dicts = { 'users': [ {'name': 'test1', 'pass': 'password1', 'permissions': [ {'access': 'yes', 'role': 'admin'}, {'access': 'yes', 'role': 'user'} ] }, {'name': 'test2', 'pass': 'password2', 'permissions': [ {'access': 'yes', 'role': 'admin'} ] } ] }

double_q = '"'

result = f"""
users = [
    {''.join([
    f'''{{
        name        = {double_q}{ d['name'] }{double_q},
        pass        = {double_q}{ d['pass'] }{double_q},
        permissions = [
            {''.join([f"{{ access = {double_q}{ d['permissions'][index]['access'] }{double_q}, role = {double_q}{ d['permissions'][index]['role'] }{double_q} }}," for index in range(len(d['permissions'])) ])}
        ]
    }},
    ''' for d in user_dicts['users']
    ])}
]"""

print(result)

其中 returns 以下行:

users = [
    {
        name        = "test1",
        pass        = "password1",
        permissions = [
            { access = "yes", role = "admin" },{ access = "yes", role = "user" },
        ]
    },
    {
        name        = "test2",
        pass        = "password2",
        permissions = [
            { access = "yes", role = "admin" },
        ]
    },
    
]

需要做什么才能在权限中的字典之间换行,同时保持空格数?即:

users = [
    {
        name        = "test1",
        pass        = "password1",
        permissions = [
            { access = "yes", role = "admin" },
            { access = "yes", role = "user" },
        ]
    },
    {
        name        = "test2",
        pass        = "password2",
        permissions = [
            { access = "yes", role = "admin" },
        ]
    },
    
]

我尝试将 f 字符串添加到 new_line 变量:

user_dicts = { 'users': [ {'name': 'test1', 'pass': 'password1', 'permissions': [ {'access': 'yes', 'role': 'admin'}, {'access': 'yes', 'role': 'user'} ] }, {'name': 'test2', 'pass': 'password2', 'permissions': [ {'access': 'yes', 'role': 'admin'} ] } ] }

double_q = '"'
new_line = '\n'

result = f"""
users = [
    {''.join([
    f'''{{
        name        = {double_q}{ d['name'] }{double_q},
        pass        = {double_q}{ d['pass'] }{double_q},
        permissions = [
            {f'{new_line}'.join([f"{{ access = {double_q}{ d['permissions'][index]['access'] }{double_q}, role = {double_q}{ d['permissions'][index]['role'] }{double_q} }}," for index in range(len(d['permissions'])) ])}
        ]
    }},
    ''' for d in user_dicts['users']
    ])}
]"""

print(result)

但是下一行从行首变成:

users = [
    {
        name        = "test1",
        pass        = "password1",
        permissions = [
            { access = "yes", role = "admin" },
{ access = "yes", role = "user" },
        ]
    },
    {
        name        = "test2",
        pass        = "password2",
        permissions = [
            { access = "yes", role = "admin" },
        ]
    },
    
]

快速修复

您在正确的轨道上,将 new_line 变量与 str.join() 一起使用。要保持空格数,只需将它们包含在 new_line:

new_line = '            \n'

进一步思考

您可能想开始使用模板引擎,例如 Jinja

优点

  • 您无需担心(嵌套)f-strings
  • 模板字符串看起来像您想要的输出(有点所见即所得)
  • 空格控制很容易

缺点

  • 您可能需要花一些时间学习如何使用模板引擎

你的例子,用Jinja

实现

要运行以下代码,需要安装jinja2

import jinja2

user_dicts = { 'users': [ {'name': 'test1', 'pass': 'password1', 'permissions': [ {'access': 'yes', 'role': 'admin'}, {'access': 'yes', 'role': 'user'} ] }, {'name': 'test2', 'pass': 'password2', 'permissions': [ {'access': 'yes', 'role': 'admin'} ] } ] }

template_str = """
users = [
{% for user in users %}
    {
        name        = "{{ user['name'] }}",
        pass        = "{{ user['pass'] }}",
        permissions = [
{% for p in user['permissions'] %}
            { access = "{{ p['access'] }}", role = "{{ p['role'] }}" },
{% endfor %}
        ]
    },
{% endfor %}

]
""".strip()

template = jinja2.Template(template_str, trim_blocks=True, lstrip_blocks=True)
users = template.render(user_dicts).replace("'", '"')

模板字符串 template_str 基本上是您想要的输出,加上一些特殊标记({% for ... %}{% endfor %}{{ ... }})。这些标记告诉引擎如何“填空”。