2010年4月21日星期三

使用Emacs编写Python

下面要说些零散的内容,标题什么的暂且做一个引子吧。

编辑器日常用还是Sctie之类的多一些。比如目前以Notepad++为主,上手即用。最多打扮一下,熟悉下插件。不过感觉不必在编辑器的功能上注意太多。因为对这类编辑器,都只是在Scite提供的编辑控件里编辑要编辑的文本,然后再使用额外提供的功能。而IDE则是针对特定用途,对编辑器和相关组件的结合了。在GUI编程中嵌入一个编辑器控件也不是麻烦的事情。对它们的使用都可以建立在对比如Win自带的记事本之类的感觉之上。

在Unix的传统的命令行工具中,提供有ed来编辑文本。ed是交互的文本编辑工具,通过输入命令来执行文本行的编辑。而另一个工具sed流编辑器,则可用对一个完整的文本流进行处理。编程语言也可用来处理文本,比如一个专门的工具是awk,在其中充分的运用正则表达式和模式匹配。sed和awk都常作为shell编程的命令。通用的编程语言,比如Perl因为在文本处理方便丰富的功能
,也能很实用地执行对文本的操作。好了,下面可以来说vi/vim。它仍然是一个基于命令的文本编辑器,但是一个显著的差异是能够可视化的展现命令执行的效果。命令可以是基本的光标移动文本插入打开保存,也可以是对整个文本的复杂操作。可以通过vimtutor来熟悉的vim命令的使用。同时vim的插件机制使得它的用途丰富和多样起来。而其他软件中也可嵌入vim来使用。

终端下还有另一种类型的文本编辑器,例如gnu/nano和dos/edit,这里不涉及年代的讨论,而它们也确实出现的相对较晚。可视为简单的纯粹的可视化文本编辑器,除了全屏幕的文本编辑域外,也显示了可用的快捷键或者菜单。使用起来和上面最开始时说到记事本之类十分相似。下面终于说到本篇的主角了,就是Emacs。它呢,可以看作是nano的增强增肥版(好吧,nano某种意义上确实是emas简化来的)。我们可以用Emacs来编辑文本,就像用记事本一样,F10使用菜单。只不过有些略微的习惯差异,比如是先指定文件名再编辑文件,以及在GNU中影响广泛的快捷键风格。抛开些许习惯差异,拿Emacs来编辑文本也是一个很方便的事情。这个。。。除了有点笨重的感觉。

Emacs在Linux的图形界面下界面很普通,不过字体渲染得很好看,至少我看着很喜欢。菜单中的帮助下面有一个教程,可以用来熟悉一下它这种风格的使用习惯并训练一下常用的编辑操作。其实Emacs的操作也是基于命令的,不过倾向于通过一个或一组快捷键来使用命令,比如C-h就可继续帮助的操作(然后按k,v,m。。。中的一个)。如果是打开或创建一个.py文件,就进入了python的mode。明显的变化是菜单有了改变,可以使用py相关实用的命令,比如执行当前程序什么的。编辑窗口中,也会开启针对py的语法加亮和缩进方式。好吧,我承认我暂且就是拿它当文本编辑器用的,仅觉得用起来挺好使的工具而已。
话说历史悠久的Emacs用起来确实有压力很大的感觉,如果不是因为这里的关注点转到了文本编辑和python上,我可能就仅仅是知道而不会去使用到它了。因为正巧对Emacs有所了解,而手头又需要一个编辑python的工具。所以这里写到的目标就是把两样东西都好好的给用起来。
传送
http://www.gnu.org/software/emacs/tour/
http://emacser.com/
http://www.emacswiki.org/
http://forum.ubuntu.org.cn/viewforum.php?f=68&sid=8b61fab8810b7da29f44cc6d84dfec8a

修改.enacs文件,文件在home目录下,我们的配置文件就是它了。其他脚本可以放在 ~/.emacs.d/ 下。Emacs为配置文件提供了图形界面了,只不过文本的性质更方便集中修改和添加启动脚本。配置文件是自动载入的一系列命令,这些命令也可以运行程序后手动执行的。所以说配置文件其实是默认启动的程序。可以去手册查API列表配置GUI看看可设置的属性,别人写好的代码。
比如:
(setq x-select-enable-clipboard t);让emacs可以和其他程序复制粘贴


下面的操作是可选的,来安装一个扩展,这是一个不同于Emacs自带的那个的python-mode
http://www.python.org/emacs/python-mode/
这是一个elsip文件,文件开始的注释里有安装方法。
其他可以用到的若干程序,可以参见:
http://www.emacswiki.org/emacs/PythonMode
扩展的以及自带的模式属于单独的程序,需要看其自身的帮助文件或说明

以上是个工地,也仅仅是个开始而已。不过接下来更多的是在如何用编辑器更好的做要做的事情,而不是编辑器本身或离开它就没法做等等的问题。

See also
http://www.ibm.com/developerworks/cn/aix/library/au-textedit.html
维基百科中Emacs及其他编辑器的页面



下面进入本篇第二个主角Python,安装了后就运行IDLE来交互的执行代码,iptyhon相比于自带的终端交互也有了增强。
话说并不喜欢Py,因为自己固执地认为“声明>命令”,所以喜好偏向于Lisp/Scheme风格。算法可以用函数表示,数据结构用List表示,结合函数和列表也能抽象出对象。虽然在函数内也用有序的命令,但关注点整个程序的结构上的。而且函数也是一个值,可以写成List中的一个元素。只要遵守了严格语法规则作用域规则什么的,可以很方便嵌套和递归。
当然Py有它自己的风格,给我的感觉是:对它使用是基于习惯的,它的语法是对语言使用抽象,而不是语法规则的展开。从PEP上可看到通过增强语法来实现更多功能的讨论,这使得Py语言在持续发展着。作为一个图灵完备和支持C语言扩展来说是不用担心Py不能做什么的,由于语言本身的修改以及实现更多的特性,让之前写的代码就会有了新的表达方式。不过这不影响把Py作为一个工具来使用,这也是关注到语言本身的表达,而不必在意其背后的规则。当看到教程或别人的为了某个表达用了如何的语法之后,自己之后做类似的表达时也可拿来用。PEP上也有倾向把语言用法的转到语法层面的指定上来。在不断在语法层面来表达库,而没用库来补充语法特性。
这种风格使得Python成为一种很好用(重音在“用”上),详细感觉可以在《The Zen of Python》中体会(通过执行import this语句获得)。使用是要做的是把算法表达出来,至于语法实现的部分和全部则可不必在意。自己上面也说了个人的喜好,但这不影响有很实际的价值来用它,包括语法特性可相关库等众多方面的。自带库是语言的一个部分,手工或使用swig自动的可以绑定C++库。其实,也是让语言可以被看作是对第三方库和宿主的接口。
http://www.python.org/doc/
http://wiki.woodpecker.org.cn/
有两个比较实用的函数是dir和help,参数是一个字符串,需要是当前环境可访问的包,比如help('__builtin__')查看内置函数的说明。

先跑题一会儿,说点其他琐碎的方面。C++对象方面的语法是申明+定义+实现,声明表明了其结构,定义则决定了生存期和作用域,实现可以同于连接器分离开(只在乎存在,而不是顺序)。C++的这种形式和它的编译时处理是分不开的。动态语言常用字典表示对象实例,不过对象仍然是很少用字典的构造语法来创建,如果一定要这样的话可以通过原型继承和单实例类的实现。C++的模板机制实现了duck-tpye机制,一个类可以如何用那么它就能拿来用,而STL则将很多数据结构都可以按照序列来处理。动态类型语言让变量都成为一个引用,赋值语句只是用来改变绑定,而有时赋值也会是对象setter方法的一个别名,变量分为mutable和immutable,对前者的改变会影响所有应用,而对后者的修改操作是绑定到一个新的副本。JavaScript和Lua用起来很有Lisp/Scheme的感觉,被用于嵌入来表示数据的内容和操作。目前常用的C语言的是版本89和99的混合,而C++是98。
注意,这里是在说语言的特性。因为使用是使用的语法表达的特性与表达的方式,而不是语言的语法本身。喜好不妨碍对使用价值的判断。

最后,在Py的语法内来玩出些有趣的东西,尝试下略魔幻的用法。比如这个:
Py语法上表达的数据结构有tuple,list,dict(str是一种tuple),它们涉及的语法有sequence,iterator,generator。注意,它们是语法的一个部分,而不仅仅是一个类型,比如用在函数调用中

#注意,以下示例收集自一些教程。

#tuple
#immutable类型,括号可省略
>>>t=1234,5567,'hello'

#list
>>>test=[1,2,"yes"]

#dict
>>>tel={'jack':4098,'sape':4139}
>>>tel['guido']=4127

#=
>>>a,b=b,a


#slice
>>>a=['spam', 'eggs', 100, 1234]
>>>a[1:-1]
['spam', 'eggs', 'bacon', 4]

#iterate
>>>for i in range(10):
... print(i)

#generator
>>>sum(i*i for i in range(10))
285


#enumerate
>>> [x for x in enumerate(['tic', 'tac', 'toe'])]
[(0, 'tic'), (1, 'tac'), (2, 'toe')]

#zip
zip([1,4,6],[2,6,2])
[(1, 2), (4, 6), (6, 2)]

#reversed
>>>for i in reversed(xrange(2)):
... print i
1
0

#sorted
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
... print f
...
apple
banana
orange
pear


#dict
>>>dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'jack': 4098, 'guido': 4127}
>>>dict([(x, x**2) for x in (2, 4, 6)])
{2: 4, 4: 16, 6: 36}
>>>dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'jack': 4098, 'guido': 4127}

#list([iterable])
#tuple([iterable])


#in,用于for和条件判断
#function=callable object
#在2.x中range是得到list,而xrange是得到一个可用于迭代的对象。

好吧,我承认是在玩C++中语言标准的正交原则。比雅尼·斯特勞斯特魯普 告诉我们“如果两个语法可以结合使用,那么就实现这个结合使用的特性”,虽然原话不是如此。至少从我上面的尝试的感觉来看Py是可以适当的这样玩一玩,不过这不是Py的原则,Py是基于习惯用法的。

补充说一下Python中数学方面的:
长整型是支持高精度的,decimal库则用来对应小数的算法,复数complex用j做虚部。
还有非内置库比如numpy,scipy。

See Also
http://docs.python.org/library/stdtypes.html
http://docs.python.org/library/functions.html
http://wiki.woodpecker.org.cn/moin/PyAbsolutelyZipManual
《简明 Python 教程》

上个截图




接下来是补遗阶段

首先是文本字符编码相关
话说以前还真看过GBK,UTF-8,Unicode在二进制上的关系,然后尝试手工写识别转换代码(其实和没写差不多)。不过只要了解的程度,就能来冷静应对这方面的问题了。
不过感觉统一成UTF-8保存然后转成wchar处理可以免除很多麻烦。
在Emacs中的选项菜单里有,见
Python中第二行coding=utf-8,转换方面用Codec库。
See Also
http://www.hickwu.com/?p=237
http://wiki.woodpecker.org.cn/moin/PyInChinese

Emacs中也可"M-x viper-mode"使用vi的按键,阅读文件有个"view-mode"。
mode的列表,可见 http://www.emacswiki.org/emacs/CategoryModes 。

果然是很琐碎的一篇,只是感觉在提及了一些东西罢了。
教程或手册之类才是更用的多的东西。

写本文的动机是我拿Python当计算器算微积分的,这是很强力的动机来着。
文本长度现在回顾了一下,发现和以前好多篇都很一致,是巧合吧。

继续跑一段。话说迭代器呢可分为外部和内部迭代器。C++是在旧有的语法上通过迭代器对象来实现外部迭代器的。内部迭代器通常表现为.each方法,参数为一个闭包。Py本身没去实现完美的作用域和匿名函数的特性,加之追求纯粹的风格(比如不提倡嵌套)没有出现.each方法,而是使用yield,for,__iter__两个接口和一个模板方法。JavaScript因为本身由于很灵活以及兼容性问题,语言的改变变得艰难和让人接受。这使得在使用上(Ajax普及的时候)对具体功能的需要移到库的层面,众多使用方便的库几乎让JS面目全非,比如用来提供.each方法。也使得一个库的学习成本接近一个语言(虽然缺少语法上的糖衣和隐式调用),不过也让人尝试(也算触发思维)了语言更有效的使用方式。体现出来重用的不同方式的表达,不过语言差异也只是在如何实现某特性与模式上。
恩,用记事本洋洋洒洒的一大段代码也很省心的。不过那是把关注灵活易修改,以及接口和层次上了。用来表示算法的话,还是更在意语义的表达上的。所以这就算Py也有不适当的地方。
好了,我想黑Py的,也想说它确实有使用价值。怎么办呢,还是想黑它。
社区的价值有时是远大于一个语言本身的,它让人用语言到更关注的领域上去。Py的成功很大一部分可以归结到它基于社区的开发模式。
既然都写到这了,说下Ruby吧。它算Py的伙伴来着。Ry呢,有类似SmallTalk的简明核心,然后利用语法上的便利可以模拟出Perl和Java等等的使用风格(至少不必js那样版本和扩展库满天飞,还容易滞后)。社区和使用上更关注应用,而不是语言一层。
注意,以上不是在谈论差异,因为在特性层面上的并不多。这里在关注的是工具的使用价值,虽然某种意义上也算是特性提供的。比如C++的设计就是在语法层面鼓励并规范了OO,并提供了OO的一个高效实现。

最后,来一个Py的广度搜索算法,我相信这会是个让人印象深刻的例子:
...


##全文完##
Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary.
——Scheme

当然,还有另一种不容忽视的思路则是 高级语言->DSL->自然语言。然后也可去涉及CLI/GUI的人机界面的话题上。

没有评论: