Showing posts with label 软件开发. Show all posts
Showing posts with label 软件开发. Show all posts

August 25, 2007

用 Python 写了个背单词小工具

注:此“软件”已被作者开为 Google Code 项目 Rewords
背单词关键在于重复,单词能不能背得取决于你看了它多少遍。把一个单词表(wordlist)中的每个 list 分成许多个 section,反复地浏览记忆就能记住。基于此,昨晚我用 Python 写了一个背单词的小工具,暂定名 Rewords 。

#!/usr/bin/python
# Filename: rw.py

import sys

def locate (f, i, n = 1):
  if n == i:
    print f.readline()
    return f
  if f.readline() == "\n":
    return locate(f, i, n+1)
  return locate(f, i, n)

def struct (f, st = []):
  ln = f.readline()[:-1]
  if ln == "":
    return st
  return struct(f, st+[ln])

def conmat (ls, l, tmp = []):
  if len(tmp) == l:
    return [tmp]+conmat(ls, l)
  if len(ls) <= l and tmp == []:     return [ls]   return conmat(ls[1:], l, tmp+[ls[0]]) def inter (st):   '''usage: `Enter`
-
n : next word
p : prev word
d : down to next section
u : up to prev section
: jump to section
l : jump to list '''
  def term (rt, lt = [], n = 0, cur = 'n'):
    def help ():
      print inter.func_doc
      term(rt, lt, n, cur)

    def next ():
      if rt == []:
        term(lt , rt, n, 'n')
      print rt[0]
      term(rt[1:] , lt+[rt[0]], n, 'n')

    def prev ():
      if lt == []:
        term(lt , rt, n, 'p')
      print lt[-1]
      term([lt[-1]]+rt, lt[:-1], n, 'p')

    def down ():
      if n == len(st)-1:
        term(st[0], n=0)
      term(st[n+1], n = n+1)
  
    def up ():
      if n == 0:
        term(st[len(st)-1], n=len(st)-1)
      term(st[n-1], n = n-1)

    def to (p = 1):
      num = (p-1)%len(st)
      term(st[num], n = num)

    def err ():
      print " # unsupported command"
      term(rt, lt, n, cur)

    cmd = sys.stdin.readline()[:-1]
    if cmd == "q": quit()
    if cmd == "h": help()
    elif cmd == "":
      if cur == 'n': next()
      elif cur == 'p': prev()
    elif cmd == "n": next()
    elif cmd == "p": prev()
    elif cmd == "d": down()
    elif cmd == "u": up()
    elif cmd.isdigit(): to(int(cmd))
    elif cmd[0] == 'l' and cmd[1:].isdigit():
      start(int(cmd[1:]))
    else: err()
  term(st[0])

def quit (m = ""):
  if m:
    print m
    sys.exit(1)
  sys.exit(0)

def start (wl = 1):
  '''usage: python rw.py [list] [section]
The wordlist named must be separated by blank lines;
program will start with the [list] or first part of the wordlist;
the each section will contain [section] or 8 words. '''
  inter(conmat(struct(locate( \
    open(sys.argv[1] if len(sys.argv) > 1 \
      else quit(start.func_doc)), wl)), \
    int(sys.argv[3] if len(sys.argv) > 3 else 8)))

print "rw.py - Rewords 0.1a by lichray\n"
start(int(sys.argv[2] if len(sys.argv) > 2 else 1))

程序是自省的,用起来应该没问题。无参数运行 python rw.py 显示帮助。
参数1 是单词表文件名,这个文件需要被空行分解为多个 list,每个 list 的第一行是标题;
参数2 是启动时加载的 list 编号,默认为 1;
参数3 是每个 section 包含的单词数,默认为 8;
进入互交描述后参考帮助,输入 h 命令,回车。
我这儿有一个可用的单词表——Barron SAT 词表,但存在一个小 Bug,不知为什么这个词表只能加载前13个 list,想帮忙的人留个邮箱地址,我把东西都发过去。
另外 locate() 函数还不能处理 readline() 越界的情况,这部分没完成。
最后根据我的代码风格,猜猜看我最近什么语言用的比较多?

October 20, 2006

上帝是个程序员——从《黑客帝国》看软件设计

上个星期我把《黑客帝国(The Matrix)》三步曲完完整整看了一遍,联想到《UNIX程序设计的艺术》一书中所说的17条UNIX哲学,深感古老的UNIX确实是软件设计思想的集中体现。Robert Metaclf说过:“如果将来有什么技术取代了以太网,那么它仍会叫以太网。”也许,The Matrix的内部开发代号中就有"UNIX"这个单词吧!
  1. 模块性原则:写简单的,通过干净的接口可被连接的部件。相比UNIX,The Matrix绝对是一个超巨大的软件,它的设计中也充分体现了模块化思想:整个系统有后台数据库(这可是墨菲斯说的)用来存储任何物件;前台有和人脑后插座相连的输入/输出接口,当然程序还可以使用电话工作;前后台之间有由知情者们组成的控制程序,标准的MVC模式。
  2. 清楚原则:清楚要比小聪明好。The Matrix的源代码我们是没法儿研究啦。不过,整个人类世界居然能被显示在3个小小的液晶屏里,而且接线员告诉我们…他能…知道这儿有个金发美女,从这一点你应该能想像出The Matrix有多么的清晰。
  3. 合并原则:设计能被其它程序连接的程序。这个还用的着多罗嗦吗?天哪,与人类的物理接口,用手机可以和真实世界交流,通过固定电话进行接入和切断,还有那个设计近乎完美的、和外界传输意识的火车站,真是一应俱全
  4. 分离原则:从机制分离从策略,从实现分离出接口。The Matrix的实现相当复杂,但设计了很好的接口;看看墨菲斯他们使用的训练场吧,它其实是早期The Matrix版本的一个变型,程序员能很轻松地控制它(最拉风的是第一部中凭空制造的那两排枪,无敌了)这说明了The Matrix的接口设计非常简洁而有序。
  5. 简单原则:设计要简单;只有当你需要的时候,增加复杂性。The Matrix的简单恐怕初看电影的人体会不深:看这那些标志性的绿色字符就烦。但你仔细想想,这可是一个时间啊!从接线员的一些操作细节也能感受到The Matrix的简单——火线教学只需要搜索内容然后按下LOAD按钮,我晕。
  6. 节俭原则:只有当被证实是清晰,其它什么也不做的时候,才写大的程序。The Matrix的的在节俭上下的功夫我们很难研究,毕竟这只存在于源代码中。个人感觉,至少从电影上看是非常华丽的,不过那是为了票房而下的功夫。
  7. 透明原则:为使检查和调试明显更容易而设计。The Matrix的调试只提供了输出部分(安全的需要吗,设计师本人是不能搬演上帝的),在每艘飞船上都有一个GUI程序来检索它的调试信息,黑客们用它作了GIS,哈哈。
  8. 健壮性原则:健壮性是透明和简单的追随者。没有一个软件没有Bugs,但有的软件可以让Bug在关键时刻失去用武之地,比如那个火车站,即便是尼奥这样的超人也无能为力啊,只能从这个出口跑会另一个出口啊。
  9. 表现原则:把知识整理成资料,于是程序逻辑能变得易理解和精力充沛的。不知道设计师是怎样开发The Matrix的,不过从它那5个前世可以看出它的进步是卓有成效的。犯错误不要紧,把经验记下来是最重要的,不是吗?
  10. 最小意外原则:在接口设计中,总是做最小意外事情。当然The Matrix也有让人超意外的时候,比如莫罗恩手下那些打不死的程序们。但别忘了他们来自于黑客帝国的早期版本。后来的莫罗恩自己和开锁人不都是普通人吗?
  11. 沉默原则:当一个程序令人吃惊什么也不说的时候,他应该就是什么也不说。《UNIX程序设计的艺术》的作者对这个原则的解释有问题(或者是翻译问题)。沉默原则应当是这样:当一个程序按照用户已有的知识完成了工作是,他应该什么也不说。UNIX命令行的程序通通是这样,尤其是gcc。The Matrix是不是为一群人按照自己的意志控制另一群人而设计的,也不存在除维护人员以外的用户,当然不会“说”什么。
  12. 修补补救:当你必须失败的时候,尽可能快的吵闹地失败。这也就是The Matrix中偶尔出现的幻象、上帝、狼人的出现了就很快消失的原因。
  13. 经济原则:程序员的时间是宝贵的;优先机器时间节约它。无语了,The Matrix工作的硬件系统都是算法设计复杂度度量是使用的“理想计算机”,感觉起来一切都是原子操作,只有与人传输数据时有忽略不计的延迟。
  14. 产生原则:避免手工堆砌;当你可能的时候,编写可以写程序的程序。这个原则的前提是,系统本身必须是可以被自描述的,就像Lisp语言。The Matrix也是被高度自描述的,那些维护程序不都是用The Matrix本身创建的吗即便是莫罗恩或史密斯这样的大拿?利用系统本身工作可是黑客帝国的一大特色啊。
  15. 优化原则:在雕琢之前先有原型;在你优化它之前,先让他可以运行。这就是The Matrix有6个版本的原因——事实上人们讨论的最多的第一个版本就是一个原型,设计师自己也说,仅仅用作测试,后来“庄稼全死了”。
  16. 差异原则:怀疑所有声称的“唯一真理“。最后这个The Matrix版本有它的“唯一真理”,可惜设计师在努力之后仍然留下了尼奥这个“余数bug”。设计师是绝对的马克思主义者,也只有在他的眼中,世界是物质的。
  17. 可扩展原则:为将来做设计,因为它可能比你认为来的要快。The Matrix的可扩展能力具体有多强我们不得而知,不过在电影中它确实被扩展了:希安的程序员们为他们的训练场程序编写了原本不存在的应急保护模块,能让可能损坏人体的元素失去真实(什么是真实?)质地,否则尼奥第一次“跳楼”就要被摔死了。:)
《黑客帝国》绝对是一部不看人生不完整的电影,不但充满了哲理,而且对于UNIX/Linux的爱好者们而言很有感召力,不是吗?:)