引子
罗布大神最近准备用python做网站,发现python在做网站方面还是比较原始的(相对于世界上最好的计算机语言),没有session,出错显示不完善也就算了,web开发框架也是少啊(还是跟最好的语言比 不是一个数量级)。最最重要的就是 在web框架上开发网站,学习难度陡峭,这样小白们怎么吃得消,完全打乱了python简单易学的规律,所以罗布大神决定自己开发一套简单易学的web开发模式/框架,让小白们学python web编程也如鱼得水,把精力花在解决问题上,而不是学习什么狗屁框架上,我们知道框架的寿命只有三年左右,完全不值得我们把学习精力投资在框架上。
正文
首先我们知道,python做web页面,肯定要把页面/模版和业务逻辑分离,不能把业务代码和html混在一起,就像下面一样
#!/usr/bin/python
# -*- coding: UTF-8 -*-
print "Content-type:text/html"
print # 空行,告诉服务器结束头部
print '<html>'
print '<head>'
print '<meta charset="utf-8">'
print '<title>Hello World - 我的第一个 CGI 程序!</title>'
print '</head>'
print '<body>'
print '<h2>Hello World! 我是来自菜鸟教程的第一CGI程序</h2>'
print '</body>'
print '</html>'
看着就觉得很丑陋是不是,这也就讲解下原理而已,真要实际做网页,估计要累死半头牛,绝对不能实战的。俗话说,上帝的归上帝,凯撒的归凯撒,所以我们要把模版/html和业务逻辑/python分离开来,这样势必需要一套模版引擎,能把数据嵌套/替换到模版上去。 在这里罗布大神第一个想到的就是有木有现成的模版引擎可以用,我找呀找,dingo,flask我去太复杂了,有些人觉得容易,你觉得容易你去用呀,话说你给这些框架添加过一行代码么?这些框架作者是你大爷?你咋这么向着他们,说话要客观呀。反正我觉得是太难了。后来找到一个mustache的python版本,pystache。mustache是一个非常舒服的客户端/js模版引擎,我以前用起来很爽的,建议做前端的同学们可以了解下,但是在python下,各种出错,我要疯了,麻烦作者稍微用点心吧,遂放弃,算了算了,自己撸起袖子来写个模版引擎,话说我也是自称大神的人。国内自己写模版引擎或者自己写一门语言解析器的人不多吧,我弱弱的问一下。
开干
说干就干,首先想到的就是python自带的字符串format函数,在这里给大家看下例子,支持字典、列表、对象各种类型,有点接近我们的需求。大家先看看例子 ··· python2.6 开始,新增了一种格式化字符串的函数 str.format(),它增强了字符串格式化的功能。基本语法是通过 {} 和 : 来代替以前的 % 。format 函数可以接受不限个参数,位置可以不按顺序。
>>>"{} {}".format("hello", "world") # 不设置指定位置,按默认顺序
'hello world'
>>> "{0} {1}".format("hello", "world") # 设置指定位置
'hello world'
>>> "{1} {0} {1}".format("hello", "world") # 设置指定位置
'world hello world'
#!/usr/bin/python
# -*- coding: UTF-8 -*-
print("网站名:{name}, 地址 {url}".format(name="菜鸟教程", url="www.runoob.com"))
# 通过字典设置参数
site = {"name": "菜鸟教程", "url": "www.runoob.com"}
print("网站名:{name}, 地址 {url}".format(**site))
# 通过列表索引设置参数
my_list = ['菜鸟教程', 'www.runoob.com']
print("网站名:{0[0]}, 地址 {0[1]}".format(my_list)) # "0" 是必须的
怎么样?看了这几个列子,看的我热血冲动,差点就扑上去,已经很接近模版渲染引擎了 那么我们来写模版吧:模版1 mb.html长这样,是不是很清爽呀
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h1>我的第一个标题</h1>
<p>网站名:{name}, 地址 {url}</p>
</body>
</html>
程序怎么写呢?
```
#!/usr/bin/python
# -*- coding: UTF-8 -*-
#引入操作系统库
import os,sys
#输出页面文件头部
print ("Content-type:text/htmlnn")
#定义要传给模版的数据
site = {"name": "菜鸟教程", "url": "www.runoob.com"}
#打开模版文件并读取内容
file="mb.html"
if os.path.exists(file) :
f=open(file)
str=f.read()
f.close()
#渲染:数据传递给模版
str=str.format(**site)
#输出给客户端
print(str)
好了,亲们,注释写的清清楚楚,我们要用python自带的字符串库format就完成了模版的数据传递/渲染工作,但是不要高兴的太早,format虽然好用,还差点意思,别人家的模版可以支持一般的循环渲染、条件渲染的。比如我要把
list1 = ['physics', 'chemistry', 1997, 2000]这样的一个数组,甚至把一个表格
list2 = [['physics', 'zhangsan', 1998, 2001],
['math', '', lisi, 2000]
['physics', 'wangwu', 1999, 2003]]渲染
这样的渲染要累死人的吧 渲染list模版要写成,
str="{0[0]}, {0[1]}, {0[2]}, {0[3]}"
然后用 str.format(list1)来渲染,list2的模版已经复杂的我不想写了,并且有时候你根本不知道list2里边到底有几组数据,这时候模版根本没办法写,所以模版要支持一定的逻辑才好,为此,我们需要写一个更牛的format,也就是我标题写的自己写个模版引擎啦,蛤~,原来你说的模版引擎就是format,没错,嗯,不过要深加工下format,format做模版引擎还差点意思的,让我们来定义个函数,扩展format,就叫supformat吧,顾名思义,就是超级format 引入 {for 变量} 内容 {/for} 来执行循环和条件,如果变量为列表 内容会被列表的每个元素重复渲染,如果变量不存在,内容不会被渲染,如果变量不是列表 但存在,变量会被正常渲染,看说明应当一点都不绕口吧,蛤~
#!/usr/bin/python
# -*- coding: UTF-8 -*-
#str:模版字符串 list1:传入的数据,可以是字典、列表、对象
def supformat(str,list1):
pos=str.find("{for ")
if pos>=0:
# print(pos)
posend=str.find("{/for}",pos)
if posend<0:
print("need a {/for}")
return "";
prestr=str[0:pos]
endstr=str[posend+6:]
keypos=str.find("}",pos)
listkey=str[pos+5:keypos]
str=str[keypos+1:posend]
#print listkey,str
if list1.has_key(listkey) : #如果变量不存在,内容不会被选择
mlist=list1[listkey]
if type(mlist)==list : #如果变量存在 会被渲染
c=len(mlist)
tmp=""
for i in xrange(c):
tmp+=supformat(str,mlist[i])#str.format(mlist[i])
# print str, mlist[i]
str=tmp
elif mlist: #判断true or false #如果变量不是列表 但存在,变量会被正常渲染
str=supformat(str,mlist)#str.format(list['listkey'])
else: #如果变量为0或者false 不会被渲染
str=""
else: #如果变量不存在,内容不会被渲染
str=""
str=supformat(prestr,list1)+str+supformat(endstr,list1) #支持递归渲染
else:
# 检查是否字典
if type(list1)==dict :
str=str.format(**list1) #字典渲染方式
else :
str=str.format(list1) #非字典渲染方式
return str
这个模版引擎写好了,怎么样,是不是没有想想的那么复杂,老祖宗说的好“天下事有难易乎?为则难者亦易矣”,非常鼓励我们自己的程序员写自己的模版引擎,写自己的框架,发明自己的计算机语言,整天你们叫嚷着别人写的这个框架好,别人发明的那个好,跟你你什么关系,自己写的也就算了,为别人写的东西你们互相奚落,还发明了鄙视链,害不害臊呀? 好了,我们言归正传,看看这个函数怎么用,假设我们把这个函数保存在一个supformat.py的文件里,那么使用的时候,要保证这个文件在当前目录或者sys.path的目录列表里,然后就引入就可以使用了,
#!/usr/bin/python
# -*- coding: UTF-8 -*-
#引入操作系统库
import os,sys
import supformat as sp #引入supformat函数
#输出页面文件头部
print ("Content-type:text/htmlnn")
#定义要传给模版的数据
list2 = [['physics', 'zhangsan', 1998, 2001],
['math', '', lisi, 2000]
['physics', 'wangwu', 1999, 2003]]
site={"list2":list2}
#打开模版文件并读取内容
file="mb.html"
if os.path.exists(file) :
f=open(file)
str=f.read()
f.close()
#渲染:数据传递给模版
str=supformat(site) # **划重点 模版渲染使用方法**
#输出给客户端
print(str)
模版如下
{for list2}
{} {} {} {}
{/for}
怎么样,模版是不是很清爽,另外要说下 模版里边需要用大括号的地方要用双大括号转义 样式表和js的大括号要写成 {{}}
好了,罗布大神写的web渲染模版引擎就到这里,你也可以直接拿来用,或者对你写自己的程序有所启发,大家如果要学习python也可以来咨询我,可以关注微信: 预约猫 然后输入罗布大神 就会有我的联系方式哦