资讯专栏INFORMATION COLUMN

web.py源码分析: 模板(1)

Rocko / 3154人阅读

摘要:模板函数到底长什么样下面我们就可以来看看模板函数到底长什么样了。当然,首先得创建一个模板文件。总结通过打印中间结果和分析代码,我们已经大概知道了的模板是如何转化成内容的。下一篇文章会阐述模板的各种语法所对应的动态函数内容。

web.py模板的实现原理

web.py的模板实现利用了Python的可执行对象的动态特性:根据模板内容和渲染函数的参数创建一个函数,该函数执行的时候会返回一个TemplateResult类实例,该实例的字符串化就是模板对应的HTML内容

实验环境搭建

为了说明web.py的模板是如何实现的,我们需要在web.py的模板实现代码中加入一些打印语句来显示中间结果。Python的virtualenv工具很好的实现了这个需求。另外,我还使用了iPython,不过Python标准命令行也是可以的。环境搭建的步骤简述如下:

创建virtualenv环境:virtualenv env

激活virtualenv环境:cd env以及source bin/activate

安装web.py:pip install web.py

这个web.py库会被安装在virtualenv环境的目录下:

(env)➜ ~/programming/python/env/lib/python2.7/site-packages/web  $ pwd
/home/diabloneo/programming/python/env/lib/python2.7/site-packages/web

下面就可以修改这个web.py的代码来看看模板到底是如何实现的。

实验代码修改

我们要修改的代码位于web/template.py文件内,找到Template类的compile_template函数(在template.py文件的第900行),加入一行打印语句:

def compile_template(self, template_string, filename):
    code = Template.generate_code(template_string, filename, parser=self.create_parser())

    def get_source_line(filename, lineno):
        try:
            lines = open(filename).read().splitlines()
            return lines[lineno]
        except:
            return None

    print code  # 这行就是我们增加的调试语句,可以打印出前面提到的动态生成的函数。
    try:
        # compile the code first to report the errors, if any, with the filename
        compiled_code = compile(code, filename, "exec")
    except SyntaxError, e:
    ...
    
模板函数到底长什么样?

下面我们就可以来看看模板函数到底长什么样了。当然,首先得创建一个模板文件。在我们的实验环境中进行如下操作:

(env)➜ ~/programming/python/env  $ ls
bin  include  lib  local
(env)➜ ~/programming/python/env  $ mkdir app
(env)➜ ~/programming/python/env  $ ls
app bin  include  lib  local
(env)➜ ~/programming/python/env  $ cd app
(env)➜ ~/programming/python/env/app  $ mkdir templates

现在,在templates目录下创建一个最简单的模板,文件名为hello.html,内容如下:

hello, world

下面来看看根据这个模板生成的函数到底长什么样子,在实验环境下启动ipython或者python,进入到app目录:

(env)➜ ~/programming/python/env/app  $ ipython
WARNING: Attempting to work in a virtualenv. If you encounter problems, please install IPython inside the virtualenv.
Python 2.7.8 (default, Oct 20 2014, 15:05:19)
Type "copyright", "credits" or "license" for more information.

IPython 1.0.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython"s features.
%quickref -> Quick reference.
help      -> Python"s own help system.
object?   -> Details about "object", use "object??" for extra details.

In [1]:

执行如下代码就可以看到模板函数的内容:

In [3]: hello = web.template.frender("templates/hello.html")
# coding: utf-8
def __template__():
    __lineoffset__ = -5
    loop = ForLoop()
    self = TemplateResult(); extend_ = self.extend
    extend_([u"hello, world
"])

    return self

In [4]:

上面的函数__template__()就是我们增加到web.py库中的那行print code所打印出来的。从这个函数的定义,我们可以看出:

函数内使用了一些预定义的对象:ForLoop,TemplateResult等。

函数的结果是返回一个TemplateResult实例。

那么,现在问题来了:

这个函数是如何生成的?

使用的这些预定义名称从哪里来的?

TemplateResult实例的字符串表示如何变成HTML文本的?

本文先来说明TemplateResult实例是如何产生HTML文本这个问题。

TemplateResult

TemplateResult类的定义也在web/template.py文件中,继承的类和实现的方法如下:

class TemplateResult(object, DictMixin):
   __delattr__ : function
   __delitem__ : function
   __getattr__ : function
   __getitem__ : function
   __init__ : function
   __repr__ : function
   __setattr__ : function
   __setitem__ : function
   __str__ : function
   __unicode__ : function
   _prepare_body : function
   keys : function

其中DictMixin是一个实现了大部分字典操作的类,继承该类的子类(也就是这里的TemplateResult)需要实现:__getitem__(), __setitem__(), __delitem__()和keys()方法,以便对象可以模拟完整的字典操作。需要说明的是:DictMixin类已经过时了,现在应该使用collections.MutableMapping类(该类的实现利用了abc库--抽象类)。

先来看__init__()函数,

def __init__(self, *a, **kw):
    self.__dict__["_d"] = dict(*a, **kw)
    self._d.setdefault("__body__", u"")

    self.__dict__["_parts"] = []
    self.__dict__["extend"] = self._parts.extend

从初始化函数可以看出,TemplateResult大部分属性都存储在_d这个字典中,该字典至少包含一个元素body。所以,外部代码对TemplateResult的对象属性进行增删改查操作时,实际上都是在操作内部的_d这个字典。初始化函数中定义的另外两个属性是:_parts,一个序列;extend,指向_parts序列的extend()方法,也就是说调用TemplateResult实例的extend方法实际上是调用实例属性_parts的extend方法。这个extend方法我们在前面的__template__()函数已经见到过了:

def __template__():
    __lineoffset__ = -5
    loop = ForLoop()
    self = TemplateResult(); extend_ = self.extend
    extend_([u"hello, world
"])

    return self
    

这个函数定义了extend_ = self.extendextend_把模板的内容添加到了self._parts这个序列中。

下面来看一下TemplateResult如何生成HTML内容,这个就要看__str__()方法了:

def _prepare_body(self):
    """Prepare value of __body__ by joining parts.
    """
    if self._parts:
        value = u"".join(self._parts)
        self._parts[:] = []
        body = self._d.get("__body__")
        if body:
            self._d["__body__"] = body + value
        else:
            self._d["__body__"] = value

def __str__(self):
    self._prepare_body()
    return self["__body__"].encode("utf-8")

主要操作是在_prepare_body()函数里,主要操作是把_parts中的字符串拼接起来,然后再拼接到body的内容后面。

看过TemplateResult的实现后,我们可以知道,由模板生成的__template__()函数最终会把一堆字符串添加到TemplateResult实例中,然后再通过实例生成HTML字符串。

总结

通过打印中间结果和分析代码,我们已经大概知道了web.py的模板是如何转化成HTML内容的。下一篇文章会阐述web.py模板的各种语法所对应的动态函数内容。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/45359.html

相关文章

  • web.py源码分析: 模板(2)

    摘要:上一篇文章源码分析模板说明了的模板的大致工作原理。本文重点讲述模板支持的语法是如何转换生成函数的。模板的名称统一是。模板代码断行模板内容函数内容从结果来看,模板中的断行只是为了不再结果中插入一个多余的换行符而已。 上一篇文章web.py源码分析: 模板(1)说明了web.py的模板的大致工作原理。本文重点讲述web.py模板支持的语法是如何转换生成__template__函数的。 we...

    figofuture 评论0 收藏0
  • web.py源码分析: 模板(3)

    摘要:前两篇文章主要说明了的模板系统将模板文件处理后得到的结果函数。生成函数的代码这个是模板生成过程中最长最复杂的一段,会应用到的分析功能以及动态编译功能。参数都是一个,表示还未解析的模板内容。 前两篇文章主要说明了web.py的模板系统将模板文件处理后得到的结果:__template__()函数。本文主要讲述模板文件是如何变成__template__()函数的。 Render和frende...

    OnlyMyRailgun 评论0 收藏0
  • 基于Linux环境的Web.py框架介绍

    摘要:前言在文章基于环境搭建框架方法介绍中介绍了客户端和服务器的交互过程,服务器接收客户端的请求后,由应用服务器对浏览器的请求进行处理,将生成的响应传递给服务器,再由服务器返回给客户端。 前言 在文章《基于Linux环境搭建Nginx+uWSGI+Python框架方法介绍》中介绍了客户端和Web服务器的交互过程,Web服务器接收客户端的请求后,由Web应用服务器对浏览器的请求进行处理,将生成...

    caikeal 评论0 收藏0
  • newrelic python agent 源码分析-1

    摘要:是应用性能管理监控解决方案提供商。目录是列出的命令脚本所在目录。包含文件如下的函数是命令执行的入口。而对于硬件信息的检测则由进行。文档地址源码仔细看下去,太复杂了。下一篇再分析一个请求到结束探针工作的完整过程吧。 Newrelic 是APM(Application Performance Management)(应用性能管理/监控)解决方案提供商。项目中,通常用它来追踪应用的性能。最近...

    szysky 评论0 收藏0
  • web.py源码分析: application(1)

    摘要:本文主要分析的是库的这个模块中的代码。将结果转换成一个迭代器。函数函数的定义如下位置位置位置该函数的参数中就是,是路由映射表则是,是本次请求路径。位置,如果是其他情况,比如直接指定一个类对象作为处理对象。 本文主要分析的是web.py库的application.py这个模块中的代码。总的来说,这个模块主要实现了WSGI兼容的接口,以便应用程序能够被WSGI应用服务器调用。WSGI是We...

    edgardeng 评论0 收藏0

发表评论

0条评论

Rocko

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<