Sunday, December 1, 2013

mako二三事 -- 函数二


五、调用其他模板中的函数

mako也能支持调用其他模板中的函数,因此,多个函数可以集合成一个mako函数库。不过mako仅支持顶层函数的跨模块调用,而且需要通过namespace标签来引入,例如,在mystuff.html中定义了一个函数account:

<%namespace name="mystuff" file="mystuff.html"/> 

如上定义之后,就可以使用

${mystuff.account()}

来调用该函数了。这种方式看起来跟python中的import XXX as XXX 是一致的。不过mako的实现还是不一样的,我们来看一下这个模板编译之后的代码:

def _mako_get_namespace(context, name):
    try:
        return context.namespaces[(__name__, name)]   # namespace缓存机制,如果已经存在,不需要再载入这个namespace
    except KeyError:
        _mako_generate_namespaces(context)
        return context.namespaces[(__name__, name)]
def _mako_generate_namespaces(context):
    # SOURCE LINE 3       # namespace语句对应的生成语句,每个namespace语句分别生成。
    ns = runtime.TemplateNamespace(u'mystuff', context._clean_inheritance_tokens(), templateuri=u'mystuff.html', callables=None,  calling_uri=_template_uri)
    context.namespaces[(__name__, u'mystuff')] = ns    # 将namespace缓存到context中

def render_body(context,**pageargs):
    __M_caller = context.caller_stack._push_frame()
    try:
        __M_locals = __M_dict_builtin(pageargs=pageargs)
        mystuff = _mako_get_namespace(context, 'mystuff’)      # 从namespace中取得该函数,即可使用
        __M_writer = context.writer()
        # SOURCE LINE 2
        __M_writer(u'\n')
        # SOURCE LINE 3
        __M_writer(u' \n')
        # SOURCE LINE 4
        __M_writer(unicode(mystuff.account()))    # 函数调用
        __M_writer(u'\n')
        return ''
    finally:
        context.caller_stack._pop_frame() 

python支持from XXXX import XX, XXX这种import方式,mako也支持类似方式,如:

<%namespace file="mystuff.html" import="foo, bar"/> 
<%namespace file="mystuff.html" import=“*"/>  


六、在python中调用模板函数

mako支持通过python程序来调用模板函数,这种方式在某些特定场合可以使用。如:

from mako.template import Template

template = Template("""
    <%def name="hi(name)">
        hi ${name}!
    </%def>

    <%def name="bye(name)">
        bye ${name}!
    </%def>
""")

print template.get_def("hi").render(name="ed")
print template.get_def("bye").render(name="ed") 


七、嵌套函数

mako也可以像python一样支持嵌套函数,而且其作用也跟python中的一模一样,编译成py文件后也是嵌套函数,因此其中变量的作用域也跟python中的类似。注意,内嵌的函数不能被其他模块引用。
<%
    x = 12
%>
<%def name="outer()">
    <%
        y = 15
    %>
    <%def name="inner()">
        inner, x is ${x}, y is ${y}
    </%def>
    ${inner()}
    outer, x is ${x}, y is ${y}
</%def>
${outer()} 

输出:
inner, x is 12, y is 15 
outer, x is 12, y is 15 

在上面代码中,还需要注意的一点是,这里的x并不会生成一个全局的变量,在模板里写的所有内容都会被包括在一个叫render_body的函数里面,如果需要在多个模板之间传递、共享一些数据需要使用特殊的技巧,这个在Context里面会讲到。

No comments:

Post a Comment