PyH源码解析(1)

in #cn6 years ago

前言

PyH是什么,以及它有什么用,在之前的博文中有说明:《Python语言PyH模块生成HTML文档使用说明》。
我为什么要写这篇文章呢?并不是基于崇高的乐于分享的心理,主要还是为我自己服务。我发现已经读懂的别人的代码,包括我自己写得代码,时间一长,就忘记了,再阅读源码,虽不至于像全新的一样,还是要耗费很多的精力。所以,我就想把代码的设计思路写成文档,也许会好一些。
为什么要写单独的文档呢?为什么不用良好的代码注释搞定呢?我发现这很困难,代码是平面的,难以反映立体的、更高层次的设计意图。另外,也很难嵌入直观的图表和示意图。

生成Tag对象

描述源码的设计思路有很多方法,我偏向于实例法。不直接描述设计的结果,而是先描述设计的目标,设计的思路,设计的原因。基于这个考虑,我就从使用者的角度、从外在特性出发,来逐步显现设计的轮廓。
我们先看一个用户的使用场景:

>>> a=div()
>>> print(a)
<div>
</div>

类工厂

很明显,div是一个对象,最简单的设计思路是定义一个div类。可是,Tag对象有很多,它们的行为特征也类似,一个个的定义,既繁琐又重复,所以需要动态向模块中注入Tag类的定义。下面就讲一下主要过程。

#设置Tag列表
tags = ['html', 'body',...]
#获取当前模块对象
thisModule = modules[__name__]
#为模块对象增加Tag属性,其中t表示枚举tags中的tag
#需要注意的是,setattr除了设置属性的值,如果属性不存在,还可以增加一个新属性
setattr(thisModule, t, TagFactory(t))
#这里面有一个重要技巧,下面的函数,返回一个类对象,这个类对象被赋予tag属性的值
#所以,当a=div()时,div就是一个属性,它等于一个类对象,所以,div()表示生成一个div对象,它继承自Tag对象
def TagFactory(name):
    122     class f(Tag):
    123         tagname = name
    #__name__:表示类的名字
    124     f.__name__ = name
    125     return f

打印Tag

一个Tag,形如<div id='abc'>xx<div/>,那么打印的逻辑就很清楚了。形如<{tagname} {属性字符串}> 内容或者子TAG <tagname/>

  • tagname:所以,Tag对象就有一个tagname属性成员,它就是形如div的字符串。
  • renderAttr():这个函数就是显示属性字符串的。
  • 内容或者子Tag以后再讲
  • Tag的结尾,这个比较简单,就不讲了。

这段实现代码,有一些地方我觉得需要重构一下。

  • selfClose():这个函数的作用是判断这个Tag是不是自己Close的,比如<input xxx />。我想修改的地方是函数名,我建议返回bool值的函数都应该使用Isxxx,Ruby语言中可以在函数名后面添加?表示返回bool值,但是python不支持,所以我的习惯是前面加上Is,表示判断。
  • self.IsSelfClose*‘/’:这里使用bool值乘以一个字符,给我造成了困扰,通过查阅,发现True就是1,False就是0,就相当于1或者0乘以一个字符,我觉得这种小技巧不是必要的,会引起混淆。不如改成:'' if(self.IsSelfClose) else '/',其实我觉得这种语法也很怪,为什么不用其他语言常用的三目运算符呢?形如:self.IsSelfClose?'':'/',不是更直观简洁吗?