2004年11月30日

有些新特性在我以前的Blog中已经描述过了,详见:这里


还有其它一些特性,看 Python.org 中的 What’s new in 2.4 已经很清楚了,还有我比较感兴趣的就是:



  • difflib 可以将比较结果生成Html文档

  • CJKCodecs, subprocess, cookielib(原ClientCookie)模块都已经包括在2.4中了

有时间用一用。

2004年11月27日

BlogShares 是一个网站,它收集了大量的Blog站点,并且以一种游戏的方式,把每个Blog看成公司,每个公司有它自已的股票,你可以投资,可以显示每个Blog的价值。我是偶然发现的,我的Blog在上面的链接是:
http://www.blogshares.com/blogs.php?blog=http://www.donews.net%2Flimodou%2F
你可以看一看能不能找到你的。没太仔细看,但好象很有趣。

2004年11月15日

六、模板关系图


Meteor 有一个很有意思的地方就是可以生成模板关系图,从图中可以看出有哪些模板,每个模板调用了哪些子模板和外部模板变量,模板之间相互引用的关系。在前面几篇Blog中的图形就是使用这一功能生成的。首先要调用模板对象的writeDot方法。它会生成 Graphviz 的 dot 文件格式,然后使用 Graphviz 工具生成想要的图形即可。


只要加入:



template.writeDot(file(‘ex02.dot’, ‘w’))


template是模板对象。writeDot需要一个文件对象,以读方式打开。


这样就生成一个dot文件。


然后生成图形文件:



dot -T png ex02.dot -o ex02.png


图形生成好了。


例子不再提供了,使用以前的例子改一改就行。


有兴趣可以看一下我以前写的Blog,关于 Graphviz 的。Graphviz — 结构表现的图形绘制工具。更多的例子可以看zoomquiet写的 http://wiki.woodpecker.org.cn/moin.cgi/Zoom_2eQuiet

2004年11月12日

这几天写Blog都是先在 NewEdit 中写的,但没有保存。因为我想NewEdit在退出时会问我存不存的。但发现退出时虽然提示要不要保存,但结果都是没存上。出现了两次,东西都丢了。原以为是点错了,但后来发现是bug,现已更正。需要的可以从 cvs 中下载最新的代码。或到这里下载最新的snapshot版本。现在一般我有更新都会放一个snapshot版本。

有问题可要告诉我呀。

五、数据驱动


在上一篇文章中我们已经了解了,不同的数据集提供方式会导入不同的替换行为。那么,除了改变一个变量的定义级别可以改变对变量的引用外,还有什么特点呢?那就是可以实现循环。有人在我的Blog留言中说加入循环就更方便了。其实已经实现了,但它是通过所提供的数据形式来实现了。而不是象其它的模板语言,有循环的特殊关键来实现这一点。这是两种不同的思路,在功能上也可能不如模板语言强大,但对我来说功能可能已经足够了。而且其它的功能也可以通过先处理出结果,再进行简单替换来实现。可能实现不是很方便,但一样可以解决问题。


就拿上一篇文章所举的最后一个例子来说,我们改变数据集的表现为:



vars = {
        ‘program’:{‘hello’:[
            {'email':'chatme at 263.net'}, 
            {'email':'your@abc.com'}
            ]
        },
        ‘username’:'limodou’,
        ‘info’: ‘your information’

   


输出结果为:



message = input_raw(“Please input limodou your information:”)
print “Hello, limodou(chatme at 263.net)Hello, limodou(your@abc.com),”, message


可以看出,由于我们为hello模板的email提供了两个值,结果hello模板循环了两次。而username在hello模板中没找到,因此到上层去找了。


在提供多个值时,要组织为列表的形式,每个值为一个字典。因此上面是两个字典的一个列表。


再如我们把usename也放到循环中:



vars = {
    ‘program’:{’hello’:[
        {
            'username':'zhangsan',
            'email':'zhangsan@abc.com'
        }, 
        {
            'username':'lisi',
            'email':'lisi@abc.com'
        }
        ]
    },
    ‘username’:'limodou’,
    ‘info’: ‘your information’


替换结果为:



message = input_raw(“Please input limodou your information:”)
print “Hello, zhangsan(zhangsan@abc.com)Hello, lisi(lisi@abc.com),”, message


可以看出,在处理hello时都用的同一级别的变量,而在处理message时,因为没有对应级别的username变量,因此使用上一级的username变量。


注:上面的大括号为了发布全部为全角字符,如果你拷贝运行需要换成半角(donews的bug)

四、层次数据集


前面提到,因为模板是层次关系的,因此在提供外部变量值时要按照层次的关系来提供数据。当一个模板同时有多个外部变量时,你需要同时提供这多个变量的值,也就是把同时存在的外部变量所对应的值组织成一个数据集。下面给出一个复杂的示例。



from meteor import T


hello = T(“Hello, <#username#>(<#email#>)”)
message = T(“Please input <#username#> <#info#>:”)
program = T(“”"message = input_raw(“<#message#>”)
print “<#hello#>,”, message
“”")


模板关系图为:



可以看出,program同时引用hello和message两个子模板。hello同时引用username和email两个外部变量。message同时引用info和username两个外部变量。那么一个测试例子为:



from meteor import Template


if __name__ == ‘__main__’:
    vars = {
        ‘program’:{
            ‘hello’:{
                ‘username’:'limodou’,
                ‘email’:'chatme at 263.net’,
            },
            ‘message’:{
                ‘username’:'zhang’,
                ‘info’: ‘your information’
            }
        }
    }
    
    template = Template()
    template.load(‘ex02.py’, ‘python’)
    print template.value(‘program’, vars)


可以看出hello和message所用的外部变量值是同时提供的,尽管它们引用的外部变量有相同的变量username。一旦分别提供数据集,那么替换的结果也可以是不一样,因为是用在两个子模板中的。结果如下:



message = input_raw(“Please input zhang your information:”)
print “Hello, limodou(chatme at 263.net),”, message


如果username就是想要一样,那么可以把username的值设成一样。还可以把username在dict中的位置提升一层,这样数据结构变成:



    vars = {
        ‘program’:{
            ‘username’:'limodou’,
            ‘hello’:{
                ‘email’:'chatme at 263.net’,
            },
            ‘message’:{
                ‘username’:'li’,
                ‘info’: ‘your information’
            }
        }
    }


在Meteor中,在替换一个外部变量时,你在当前的模板级别中进行查找,如果没找到,会到它的上级变量中进行查找。上面的数据就是把username由最底层放到了模板同一个层次。因此在替换hello和message时,当在当前级别中找不到时,就上升级别,如果找不到再上升级别。因此,可以把多个模板都要使用的外部模板变量提高它的级别,这样就可以让引用它的模板都使用相同的值。如果不相使用相同的值,那么就需要在相应的级别进行变量值的定义。如果全放在顶层,那么就与简单模板没有区别了。如可以这样:



    vars = {
            ‘username’:'limodou’,
            ‘email’:'chatme at 263.net’,
            ‘info’: ‘your information’
    }


因此Meteor是数据驱动的,数据定义的形式决定了模板替换的行为。


注:上面的大括号为了发布全部为全角字符,如果你拷贝运行需要换成半角(donews的bug)

在上文我已经介绍了简单的模板,而且模板变量的开始和结束串都可以进行修改。那么现在再给出一个通用的例子。在许多模板处理系统中,模板变量一般定义为:



$var


的形式。那么在Meteor中也可以实现这种模板变量的定义,只要修改这行语句为:



template.load(‘ex01.tml’, ‘text’, r’\$’, r’\b’)


可以看出起始符为:r’\$’ ,因为在 Meteor 中,一个模板变量是使用正则表达式来进行处理的。而 $ 在正则表达式中有特殊的涵义,因此要使用转义符。


结束符为:r’\b’。这表示结束在单词的边界。


三、层次模板


Meteor不仅仅支持简单地不分层次的模板,而且还支持分层次的模板。所谓分层次就是在一个模板文件中,可以同时定义多个模板,这些模板之间可以相互引用。但Meteor不支持环状引用,只支持树状引用。在Meteor中已经预置了使用 Python 的模板,它支持层次模板定义。下面给出一个例子:



1     from meteor import T
2
3     hello = T(“Hello, <#username#>”)
4     message = T(“Please input welcome message:”)
5     program = T(“”"message = input_raw(“<#message#>”)
6         print “<#hello#>,”, message
7     “”")


可以看出这根本就是一个程序。因为使用 Python 语句可以很容易地实现模板的定义。而如果使用文本表示,必然要引入一些特殊的符号来区分模板和模板的值。当然这只是我的考虑,你完全可以从 Meteor 的类中派生自已的模板处理器,用于生成模板对象。这是后话以后再提。


第1行 从meteor模块中导入模板类T
第3行 定义模板hello。可以看出其中定义了一个模板变量username
第4行 定义模板message。它没有包含任何模板变量
第5-7行 定义模板program。它包含了message和hello模板变量,由于它们又是模板名,因此program引用了两个子模板。


从上面的模板定义可以看出,这个模板是分层的,program处于最顶层。message和hello处于中间层。而username没有对应的模板,因此在Meteor中,定义这种为外部模板变量,它是需要用户提供相应的数据的。这一点和简单模板提供数据是一样的,不过,一般需要提供层次形的字典值。


这是使用Meteor生成的模板关系图:



可以看出模板之间的关系。圆形为模板,方形为外部模板变量。


下面给出模板替换的一个例子:



1     from meteor import Template
2
3     if __name__ == ‘__main__’:
4         vars = {’program’:{’hello’:{’username’:'limodou’}}}
5
6         template = Template()
7         template.load(‘ex02.py’, ‘python’)
8         print template.value(‘program’, vars)


第4行 生成外部模板变量值,按模板引用顺序生成字典值。
第7行 第一个参数为 Python 形式的模板文件名。第二个参数为模板类型,此处为 ‘python’ 类型。


生成结果为:



message = input_raw(“Please input welcome message:”)
print “Hello, limodou,”, message


上面提供数据可以简化为:



vars = {’username’:'limodou’}


注:上面的大括号为了发布全部为全角字符,如果你拷贝运行需要换成半角(donews的bug)

2004年11月10日

Meteor 是我开发的一个模板处理系统,在我以前的 Blog 中已经有介绍。不过,最近做了一些修改,我会在这几篇 Blog 中详细进行介绍,希望它对你们有用。要注意的是,Meteor是一个模板替换系统,它不提供某种模板替换语言,因此在功能上并不强大,但在某些简单的环境中已经足够应付了。


一、下载安装


Meteor现放在啄木鸟社区上,大家可以到这里去下载,上面还有一些我以前写的一些文档。因为程序发生改变,以前的示例有些已经不可用了。


安装很简单:



Python setup.py install


二、简单模板示例


一般的模板可能很简单,就是一段文本中加入一些我称之为模板变量的东西组成。模板变量在Meteor是这样的字符串:<#variable#>。其中<#是开始字串,#>是结束字串,variable是变量名。而且在Meteor中你可以改变开始和结束字串,在后面的示例中我们会看见。


比如有这样一个模板文件(ex01.tml):



title=<#title#>
body=<#body#>


这时我想将title替换为’This’,将body替换为’This is a test.’


程序是这样的:



1       from meteor import Template
2      
3       if __name__ == ‘__main__’:
4           vars = { #应为半角符,这里是全角
5               ‘title’ : ‘Test’,
6               ‘body’ : ‘This is a test.’
7           }#应为半角符,这里是全角,不然发表不了
8          
9           template = Template()
10          template.load(‘ex01.tml’, ‘text’)
11          print template.value(‘text’, vars)


第1行     从meteor模块中导入Template类
第4-7行 定义要替换的值,使用字典来处理,一个变量对应一个值
第9行     生成模板对象
第10行   装入模板,文件名为ex01.tml,类型为’text’
第11行   打印替换后的模板内容。’text’为简单模板的模板名(在Meteor中,一个模板对象可以处理多个模板,因此要指下要处理的模板名。对于简单模板系统定义为text。其它格式的模板可以自定义。)。vars为使用的模板变量的值。


上述程序的运行结果为:



title=’Test’
body=’This is a test.’


如果模板文件改为:



title=$title$
body=$body$


只要把第10行改为:



template.load(‘ex01.tml’, ‘text’, ‘$’, ‘$’)


得到的结果与上面相同

http://wxpython.sourceforge.net 看一看吧,新版本的 wxPython 发布啦。看看最近更新也没有什么太多的东西,增加了几个控件,支持多版本共存,这可能是一个大的改动,其它都是一些零碎的改动。不过,以前我说过的保存文件时,文件名后缀有问题的 Bug 好象解决了。大家快升级吧。


这次下载与以前不一样了,执行部分与文档、示例已经分开了。而且文档、示例不再安装到site-packages目录下了,在windows下是装到porgram files目录下了,请注意。

听说过 JPype 吗?下面是它主页上的说明(简单翻译,不对之处望见谅):






JPype is an effort to allow Python programs full access to java class libraries. This is achieved not through re-implementing Python, as Jython/JPython has done, but rather through interfacing at the native level in both Virtual Machines.


JPype 是一种努力,它允许 python 程序全面访问 java 的类库。它的实现不是通过对 python 的重新实现(象Jython所做的那样),而是通过在两个虚拟机之间实现本地级别的接口。


Eventually, it should be possible to replace Java with python in many, though not all, situations. JSP, Servlets, RMI servers and IDE plugins are good candidates.


最终将可能在许多地方(不是全部)用 Python 来替代 Java。象Servlets, RMI服务和IDE插件等都是很好的选择对象。


Once this integration is achieved, a second phase will be started to separate the Java logic from the Python logic, eventually allowing the bridging technology to be used in other environments, I.E. Ruby, Perl, COM, etc …


一旦这个集成被实同现,第二阶段将开始把 Java 的逻辑从 Python 逻辑中分离出来,最终允许这种桥技术(bridging technology)可以应用于其它的环境,例如:Ruby, Perl, COM, 等等…


Why such a project?


As much as I enjoy programming in Python, there is no denying that Java has the bulk of the mindshare. Just look on Sourceforge, the are 3267 Python-related projects, and 12126 Java-related projects. And that not counting commercial interests.


就象我喜欢用 Python 编程一样,不可否认 Java 也有着大量的经验共享。就看看 Sourceforge,那里有 3267 个 Python 相关的项目,同时还有 12126 个Java相关的项目。并且没有算上商业方面的东西。


Server-side Python is also pretty weak. Zope may be a great application server, but I have never been able to figure it out. Java, on the \ other hand, shines on the server.


服务器方面的Python是相当弱的。Zope可能是一个非常棒的应用服务器,但我还没有研究过它。而另一方面,Java在这方面很出色。


So in order to both enjoy the language, and have access to the most popular libraries, I have started this project.


所以为了享受两种语言,并且可以处理最流行的库,我开始了这个项目。


What about Jython?


Jython (formerly known as JPython) is a great idea. However, it suffers from a large number of drawbacks, i.e. it always lags behind CPython, it is slow and it does not allow access to most Python extensions.


Jython(早期称为JPython)是一个伟大的想法。然而,它也忍受着大量的缺点,例如,它总是滞后于CPython,它很慢,并且不能访问大多数的 Python 扩展。


My idea allows using both kinds of libraries in tandem, so the developer is free to pick and choose.


我的想法是允许使用两个库,所以开发者很自由地可以进行选择。


我想大概意思大家应该明白了。就是在Python中使用Java的库,这一点很象 python.net 的想法,从两者中取其长。