論如何自己寫一個Python的模板語言

胡建飛發表於2020-11-11

論如何自己寫一個Python的模板語言

核心關鍵

exec(source[, globals[, locals]])

使用見 python3 exec函式

import re


html = "<h1>{{msg}}</h1>"

# 先分離普通字串和模板語句
tokens = re.split(r"({{.*?}})", html)
# ['<h1>', '{{msg}}', '</h1>']

# 拼接函式字串
"""
當tokens = ['<h1>', '{{msg}}', '</h1>']時
拼接一個函式字串, 如下所示
def render(context):
    result = []
    result.append('<h1>')
    result.append(str(context['msg']))
    result.append('</h1>')
    return "".join(result)
"""

# 建立單行程式碼列表
func_code = []
func_code.append("def render(context):")
func_code.append("    result = []")  # 注意縮排

# 依次新增
for token in tokens:
    if not token:
        # 空忽略
        pass
    if token.startswith("{{"):
        # 表示為模板變數語句
        func_code.append(f"    result.append(str(context['{token[2:-2]}']))")  # 2:-2去掉首位花括號
    else:
        # 普通字串
        func_code.append(f"    result.append({repr(token)})")
        
# 最後新增return語句
func_code.append("    return ''.join(result)")

# 使用exec執行func_code
namespace = {}
exec("\n".join(func_code), namespace)  # 這時render函式就載入進namespace內了

# 呼叫render函式
context = {"msg": "Hello world!"}  # 傳入的變數集
result = namespace['render'](context)

print(result)
# <h1>Hello world!</h1>
    

未完待續

相關文章