python string template:带有正确缩进的多行替换

时间:2016-06-10 14:42:33

标签: python templates newline

我使用string.Template来生成Python代码。模板可能看起来像

import numpy

def main():
    ${content}
    return

用多行字符串替换${content}时,结果为

import numpy

def main():
    a = 1
b = 2
print(a + b)
    return

有道理,但当然不是我想要的。我可以使用;而不是使用换行符连接语句,但为了便于阅读,我希望用正确的缩进填充所有换行符。

如何用换行符替换${content}并更正缩进?

2 个答案:

答案 0 :(得分:1)

我也在使用string.Template进行代码生成,还需要从模板获取缩进。 我的解决方案是继承string.Template的子类,并添加一种在那里获得缩进的方法。

如果将多行字符串存储为行列表,则可以使用'\n' + indent加入该列表。

使用您的示例,代码如下所示:

from string import Template
import re

class MyTemplate(Template):
    def get_indentation(self):
        self.indentation = {}
        # self.pattern is the regular expression Template uses to find the substitution patterns
        # self.template is the template string given in the constructor
        for match in self.pattern.finditer(self.template):
            symbol = match.group()
            # search whitespace between the start of a line and the current substitution pattern
            # '^' matches start of line only with flag re.MULTILINE
            pattern = r"^(\s*)" + re.escape(symbol)
            indent = re.search(pattern, self.template, re.MULTILINE)
            self.indentation[symbol] = indent.group(1)

tpl = """\
import numpy

def main():
    ${content}
    return
"""

template = MyTemplate(tpl)
template.get_indentation()

content_list = [
    "a = 1",
    "b = 2",
    "print(a + b)",
]

join_str = "\n" + template.indentation["${content}"]
content = join_str.join(content_list)
print(template.substitute(content=content))

MyTemplate.get_indentation()编译一个字典,将替换模式作为键,并将从行首到替换模式开始的空白作为值。因此,在这种情况下,字典将是:

template.indentation = {
    "${content}": "    "
}

请注意,该代码不是很有效,因为它对整个模板字符串使用正则表达式搜索,以查找该字符串中的每个替换模式。

答案 1 :(得分:0)

我可以想到几个选项,没有魔法打印这个并正确地缩进它'方法虽然。

1) 您可以在多行字符串中包含空格/换行符,如下所示:

"""a = 1
    b = 2
    print(a + b)"""

2) 您可以使用autopep8,并在生成的python文件上运行它。

3) 或者不是将其保留为单个多行字符串,而是将其保存为字符串列表并执行以下操作:

def assemble_code_string(content_list, indent):
    # assemble the content_list into a single string, prepending the indent value of spaces to each content_list
    return '\n'.join(["%s%s"%(' '*indent, line) for line in content_list])

然后将其用作${content}。这很简单,因为它假设您的内容列表中的所有行都将以相同的缩进为前缀。如果你需要,我相信你可以在它上面构建。