星期三, 三月 21, 2007

又被封了?

奇怪的事情……今天发现blogspot又上不了了,但是可以写blog(www2.blogger.com访问正常)!最坏的可能当然是GFW发作把blogspot封上了,当然最好不要发生这种事。

星期日, 三月 18, 2007

杂记

再次拾起我的传统杂记……

What Baidu says about 'SB'?
大家打开www.baidu.com,输入SB,看第一条。其他的不多说了

Technical Stuff:On Regular Expression

这个网页,用Perl的Regular Expression来解决一些NP Hard Problem,还有Sodoku

太晚了,睡觉去也。

星期一, 三月 05, 2007

Language by Keyboard

reddit.com上的一个帖子。从键盘看所使用的编程语言。

C程序员:键盘上的'*'基本上废掉了(如果真是这样,说明对指针已经到了走火入魔的地步了。这样写C程序和汇编相去不远矣。我个人没有这么牛,最多只是把printf写到近乎条件反射了)
C++程序员:键盘上的'<'和'>'已经作废(这哥们估计是Template Meta Programming的高手,一天不用template浑身不爽。也属于走火入魔)
Lisp程序员:当然是'('和')'了。
Python程序员:Tab键。谁叫Python规定了嵌套结构一定要用缩进表示呢?
Perl程序员:所有的标点符号键都报销了。而字母和数字键干净整洁,和新的一样(众所周知,Perl将键盘上那些非字母数字键发挥到了极致。我个人不欣赏这种语言设计)
APL程序员:他们有一个专门的APL键盘(现在还有人用这种恐龙级的语言?听说过这门语言的人估计都寥寥无几。为什么说他们需要一个专门的键盘?因为APL用到很多匪夷所思,根本不应该在Programming Langugae里面出现的字符,程序极其短小精悍,但外观如甲骨文,如蝌蚪文,如涂鸦,……总之令人发指就是了。属于一种彻底破坏当今IT行业对程序语言一切想象的语言。举几个例子:
找从1到N的素数:
(∼N∈N∘.×N)/N←1↓⍳N
什么意思?我没有兴趣知道。对于这样充满了火星字符的程序能够成功的用html表示出来已经让我吃惊不小。
Conway的life game:(没法用字符了。上图片)

有兴趣的同志自己上wekipedia参观。
Newbie程序员:他们的F1键坏掉了(不知道这哥们是用的什么IDE?)
Windows程序员:他们的'Ctrl','Alt'和'Delete'键早按坏了。看来这帮hacker对Microsoft真是一点也不客气啊。

还有几条我没完全明白:

文档编辑(使用Word):'e','Ctrl'和'Alt'键都不行了。谁能解释一下?
经验丰富的文档编辑(还是Word):这回是'Ctrl'和's'。还是不懂。

这个表还在不停的增长。More Language By Keyboard

星期六, 三月 03, 2007

Copy Semantics in Python

昨天晚上被Python给整得……还是自己概念不清。我想实现一个二维数组,最直接的办法就是用list,其中每个元素又是一个list。所以我就这么写了:

array2d = [[]]*n ## n is the dimension of the 2-d array

然后要往里添加元素。像这样:

array2d[0].append(1)

我很自信的认为结果肯定会得到[[1],[],...,[]]。所以根本就没去检查。整个算法跑出来得到一堆诡异的结果,然后就开始了艰苦的bug hunting。找了半天,问题集中在前面那条append语句。print出来一看,结果居然是[[1],[1],...,[1]]!看到这个输出我愣了半天,我觉得我的世界观人生观都被打碎了。问题当然出在Python的copy by reference的语义上。在通过'*'运算符复制时,复制的只是“引用”,复制出来的所有东西其实都是同一个。我当时还没把问题想明白,复制不行,咱们就累一点,一个一个添加进去!

array2d = []
for i in range(n):
array2d.append([])


这个做法是正确的,用id()检查array2d的每一个元素发现它们各不相同。然后我又犯傻了,想把它写成一个函数:

def new_array2d(n,obj):
ret = []
for i in range(n):
ret.append(obj)
return ret

结果又回到了老路上,再一次出错。

最后来总结经验:Python中的复制(这里的复制其实包括了赋值、参数传递、‘*’运算符(仅对sequence type有效)等等)是by reference的。如果复制的对象是immutable的,比如int,string,那么by reference和by value其实没有区别。但如果对象是mutable的,比如list,dictionary,那么复制就相当于C中的复制指针,这个时候要提起注意。那么为什么前面写array2d.append([])的时候不会出问题呢?表达式'[]'会导致一个新的list对象被构造出来,虽然大家都是[],但各不相同。它们是“值”相等,但“引用”不相等。这也是因为list是可变对象。其实copy by reference的语义pythonist估计都知道,但到实际编码的时候还是免不了要犯一点错。

再想想,如果真的要copy一个list,得到一个副本呢?Python给我们提供了copy模块专门来做这件事。copy提供了两个基本的函数,一个是copy,一个是deep_copy。copy.copy(obj)函数提供了Shallow Copy语义,copy.deep_copy(obj)顾名思义是Deep Copy。两者的区别相信学过C++中Copy Constructor的同志都很明白。一般情况下,用copy.copy(obj)就可以了(所以它的名字就叫copy,没有弄成shallow_copy()这样的怪胎)。这个办法我想应该比较普适。当然,对于list,我们有专门的惯用法(即切片操作[:])复制。又如字典(dict)对象,也有相应的copy方法,一般情况下不需要动用到copy模块。

Python中Copy模块的文档

终于,找到了在blogger中显示代码缩进的办法:输入全角空格。这样就不会被自作聪明的blogger把空格都去掉了。缺点是:如果有人想把代码拷贝到文本编辑器中,就会出现一堆非法字符(我相信没有哪种语言的编译器/解释器会把全角空格当作空格的)。然后就会扔出a mass of error message。所以这也只是权宜之计。或许修改css能够解决这个问题?
Update:和Python无关,终于找到了代码缩进问题的解决办法,很简单,把所见即所得编辑器关掉,直接写html,把代码放在pre标签中。

星期五, 三月 02, 2007

May God Bless GFW

我已经没有兴致再去骂GFW。我们已经习惯生活在各种限制中。在GFW出现以前,Freedom这个东西曾经存在在Internet上,现在没有了。对我个人而言,GFW让我最不爽的是它封锁了Wikipedia,我不得不用answers.com这样的曲折方式来访问。此外它还禁掉了我认为是宇宙中最好的blog服务:Wordpress.com。当然blogger也很不错。注意这几年blogspot一直都被封上,到去年下半年才解封。Wordpress现在又提供了对LaTeX的支持。这更增加了我对Wordpress的无限向往。我现在想在blog上写个数学公式都必须通过tex2png之类的玩意做成png图片然后上传,如果想修改就得一切重来,麻烦到极点。如果blogger也能支持LaTeX,我真的想要出去喝两盅庆祝一下。最关键的是:你不知道明天起来还能不能访问blogger。既然这种事情已经发生了无数次,完全有可能再来一次。

昨晚上看到阅微堂上的一篇文章,总结了目前能够绕开GFW的各种方法。其实大家的原理都是一样的,就是通过匿名代理。代理这个东西有时效性,像衣服一样隔两天要换一换,不然被GFW察觉了就没用了。在这里把文章的内容转述一下。

Anonymous Web Proxy Server

比如http://p.free.com.do/http://grab.cc/等。通过这些匿名代理网站,访问Wikipedia,Wordpress.com基本上没有问题。但是它们不能避开GFW的关键字过滤。如果有自己的主机空间,则可以安装一个phproxy

Anonymous Proxy Software

例如大名鼎鼎的Tor。现在Tor似乎已经不行了,可能是GFW已经找到了应对的办法。所以低调一点。另外一个好用的GFW Killer是free door。由于free door出身很有问题(是某个非法协会开发的),想找个下载不太容易。我也不给链接。前面阅微堂上有下载。

总而言之,广大网友和GFW的斗争才刚刚开始。所谓道高一尺,魔高一丈,群众的眼睛是雪亮的,群众的力量是无穷的。GFW总有倒掉的一天。到那时再来效颦鲁迅,写一篇《论GFW的倒掉》。

星期四, 三月 01, 2007

Code Kata:Word Chains

又做一个Kata题目。这回是Kata 19,Word Chains,即要在字典中寻找一个单词序列,头和尾由输入决定,相邻的单词必须只能相差一个字母。例如下面是一个从cat到dog的单词链:

cat->cot->cog->dog

这个题目我想不到什么特别巧妙的算法,只能暴力搜索。但是因为输入数据量非常大,如果用递归的话会导致栈溢出,所以改用队列。最后的性能还马马虎虎。Kata上说作者的原始解答跑得很慢,用他提供的字典找从"ruby"到"code"的单词链需要90s,而"code"到"ruby"要一个小时。他后来改进了算法,上面这两个例子都可以在0.5s到1s内完成。由此可见算法的确是影响程序性能的第一要素。我的程序基本上差不多,从"ruby"到"code"耗时0.5s,"code"到"ruby"稍微长一点,大概1.8s,可见算法还有改进的余地。

wordchain.py

还是老办法,放到googlepages上。

现在觉得python确实好用,代码写起来很快,主要得归功于库的强大,特别是一些常用数据结构,比如list,dictionary(hash table),都是作为内建数据类型支持的。python里面唯一让我有些不爽的就是string。想要把一个string排序就得先把string转换为list,对list排序后再重新转换为string。文档上说这是因为string是imutable object,不可变对象,而list的sort方法会改变对象。那为什么不给string专门实现一个sort方法呢?可能Guido van Rossum觉得用list过渡一下进行排序也没什么不好的,再加上对string进行sort不算是特别常用的方法,就懒得实现了。