2010年11月24日星期三

认识Java - 篇一

A
先暂且只涉及Java语言本身,来列举一下参考资料:
The Java Programming Language, Fourth Edition
The Java Language Specification, Third Edition
The Java Tutorial, Fourth Edition
Java SE 6 API Javadocs
其中后三者有在线版本可以获得
http://java.sun.com/docs/books/jls/index.html
http://download.oracle.com/javase/tutorial/
http://download.oracle.com/javase/6/docs/api/
不过下面的内容仅是以这里的第一本书为基础来写一些想法。
希望可以留下若干片段来从Java中品尝出一些有趣的东西。

B
Java是一种编程语言,同时也是一个平台。最初由Sun Microsystems的James Gosling开发的,于1995年发布第一个版本。整体看起来有点像C++和SmallTalk结合的感觉,是一种运行在虚拟机JVM上的静态类型语言。开发通过JDK,将源代码编译为平台无关的字节码。Java当初针对嵌入式而产生,重视移植性和安全性,目前是服务端应用开发最为广泛使用的平台。
保持着向后兼容性,Java现在的稳定是Java6,且已得到普遍的部署。从发展历史上说1.1/1.2/1.5是较重要的几个版本,由于其中新特性的引入使得代码的编写产生了新的习惯。本文将依照Java5的规范来说明,对旧的代码将不再提倡,具体细节会在下文中有所提及。

C
凭着自己之前对C++的感受,编译时间实在很痛苦。而在Eclipse的增量编译中,构建会随着代码的修改而自动完成。使得源代码保存之后,便可以立即直接执行。
关于编辑器,之前用到了Geany这个很平凡而使用的文本编辑器。话说初学应该拿语法高亮都没有的记事本的,可以减少干扰和依赖。然后用了Sun的NetBeans,其优点是开箱即用。通过它的GUI可以调用若干Java工具,同时补全的存在缓和了对类库的恐惧。目前还是转到了喜欢的Eclipse上来了,一个顺手的环境可以使代码的编写更为轻快。
Eclipse支持Emacs风格的按键,可以安装更多插件,并且有很好用的代码导航和重构功能。之前对C++和Python自己也把它视为终极IDE的,除非目标很小让它庞大的身躯的启动得累赘。对我这种菜水平,它似乎介意我:)。

D
从C++到Java,个人起初的动力仅是想多个额外的工具写算法方便一些,此外Java的庞大的社区也是一个吸引人的要素。这样的对语言平台的扩展还是一个很平滑的过程,从可预见的收益来说,虽然是盲目乐观了一些,但也可以说是差不多是值得的。
在TJPL一书中,除去开篇那段和TC++PL一样是K&R风格的概括性教程,内容是从OO开始的。先介绍了对象的使用和类的扩展,然后才转向表达式和控制流程。这和TC++PL正好顺序相反,C++是扮演着一个OO的推动者的角色,而在Java中已经把OO视为了理所当然的,或者说是本能的事情了。类库方面两者都是作为垫后内容来说。
虽然Java都C++都可以通过各自的标准库来做到很多的事情,不过Java的库要丰富得多。而像线程这一特性在Java中是直接从语言的层面考虑,融入了程序的执行流程之中。这使得在对Java的接触中看到一些对浅薄的C++知识来说很是新鲜的东西。
不过,C++的库也有很鲜明的特征,特别是在Boost中使用库的层面来扩充语法。它让代码显示出了魔幻的一面,使得多种范式的程序风格都可以在同一种语言中得到实现。自己接触了比较熟悉的库是Qt,它是一个GUI库,不过它也提供了语言层面的限定与扩展。其实Qt和Java有着相当大的共同点,自己一直是把Qt当作Java风格的C++来看待的。比如双方都是自Object而下的单继承结构,都有固定的getter/setter写法。由于Java的风格对其他现代语言有着无法回避的影响,这样来在接触Java的时候反而有种亲切之感。

E
本文的分节没有很明了的原则,完全是想到哪里写到哪里。觉得差不多是一个内容了,或者篇幅差不多了,就单独作为一个段落。
记得Java的书上说过要忘记C++,因为两者之间的差别会花费不必要的经历,而且还容易带来混淆。我对这句话是很认可,两者毕竟是类似却又不同的语言,在同一个时候只会凭借一种语言的角度在思考。不过有一个差别还是要提一下,那就是指针。C语言用户有嵌套指针的习惯,并且有时以此为乐。不过这种风格在结构良好的C++程序中并不常见,阅读起来便较为清晰。恩,这样来看Java也是属于代码较容易阅读的类型。
下面说一下学习和使用间的关系,像Java这样的带着庞大的库的语言说什么完完全全掌握是一件不现实的事情。对于熟悉一种工具而言,就涉及了成本和收益之间的关系。先再把C++提上舞台,它基于了C并把OO提到语言层面来。OO是一种思想,它有它组织程序的益处,在C中并不是不可以使用。但是对C的使用者而言,即使知道OO但不熟悉OO的话,它很可能不会去OO。而在C++中OO成为了语言的一部分,并有了一致的实现方式。这使得C++的使用者对OO有所学习,并在实际的项目中运用OO的益处。就像现在ROR让Web应用的MVC普及一样,因为它提供了易于接受的方式,并且让其他平台上也转入对同样模式的使用。
这里想说的是,学习是有目的,但也是有偏泛的。在现实生活中不是一种保守型的一对一关系,作为一个工具来说人们是使用他熟悉的东西来解决不熟悉的问题。本文虽然很散乱,但还是参照了很系统的书目来写的。依照着Java的风格使用他,而不仅仅是抽取着语言的部分。不会去像从C++中抽取了已知的C部分,然后便以此为全部地使用C++。也不会因为看到了其中新鲜的东西,而去忽略语言它自身成为的一个整体。这样,虽然说这里还只是在从语言层面上谈,一个从实际运用角度说还有欠缺的层面。不过毕竟,话题总得有的浅薄的开端吧。

F
先来说Stream,按字面意思就是流。单说这个字看起来有所费解,还是觉得英文单词的表意比单独的中文字要清晰一些。Stream是一个很形象的单词,它是对I/O的一种抽象方式。该项机制源自Unix系统,为输入输出、文件操作、用户交互、进程协作、网络通讯提供一致的界面。Java和C++一样,都试图在IO方面提供较C更多的抽象概念和工具,以方便统一地解决在流的使用中常见的问题。
Java中的流,按方向区分有输入流和输出流两种,按数据划分有字节流和字符流两种。其中以字节流为基础,提供了InputStream和OutputStream这两个界面。在使用Stream时我们通常关注的是界面能怎么用,而将具体类的实现方式隐藏在界面之下。这里说界面其实是不恰当的,虽然在使用时可以这样理解。因为InputStream和OutputStream实际上是抽象类,有两组对应的抽象方法叫read和write。这样做的获得的好处是,在实现自己的Stream类时只提供read(int)和write(int),而其他方法可以使用依赖于它们的默认实现。Stream类的其他方法暂不说明,其中有个要注意的是它的方法有阻塞与否的区别,这对使用流的方法的返回值有着不可忽略的影响。和字符相关的IO流是实现了Reader和Writer这两个抽象类,从抽象层次上说它们和Stream的两个抽象类是平行的。它们提供的方法在名称上相对应,并同样有着各自的不同用途的实现。其间的差异是,字符流在字符编码上是保持着统一的,这样便实现了与实际使用编码的无关性,而字符流是直接地反映了数据自身的。在字节流和字符流之间,是可以通过InputStreamReader和OutputStreamWriter来转化的。
这是因为Java中的流实现是可以通过序列的方式来使用的,以其他的流作为当前流的输入或者输出,以达到在使用某个具体的Stream时可以实现功能上的扩充。例如在输出时通过OutputStreamWriter使用OutputStream时,将对输出的字符进行编码,编码方式可以用字符串指定或者由系统默认。调用某一个流的flush或者close方法都会使得它说使用的流也被调用同样的方法,不然的话它所使用的流的read和write方法一般将只会在该流认为需要的时候被执行。在Java中还提供有Filter、Buffered、Piped、Print、LineNumber、SequenceInput、Pushback、Tokenizer,Data可作为中间流使用,他们可以最终使用ByteArray、CharArray、String、File或者其他Stream的实现作为实际IO的对象。这些中间流除了可以用来提供过滤功能外,也可提供比Stream抽象类更多的可调用方法,或者用来实现将Stream转化为不同的接口供不同的目的使用。例如对象持久化就是通过流来实现了对象的保存和传递机制。
顺便说一下,负责字符编码的包是java.nio.charset,通常是用在与外界的IO操作中。Java的char类型会一致地使用UTF-16编码,这样就在程序的内部逻辑上尽量避免编码问题了。

G
下面开始内容简略一些,既然本文的本来目的是一片流水帐,就让它更像流水帐一些吧。想到关于Java语言本身有趣的或者说是值得关注的东西记录下来一些,想来随着这段时间的记忆过去也可以发掘其中遗留下的些许价值吧。
Java是直接提供对线程的支持的,一个线程即一个Thread对象。我们的方法main是被默认创建的一个线程,它可以调用其他Thread对象的start方法,让线程对象的run方法可以和自己同时执行。也就是说他们中的任何一个方法陷入阻塞或者死循环,其他执行着的方法依然可以不受影响的运行。自己的run方法可以通过派生Thread类实现,或者在单继承的限制中去派生Runnable后用来构造Thread对象。
当同时运行的线程要使用同一个数据时,如果该项操作不是原子的,那么可能会造成互相依赖的一组操作之间混入其他进程的数据。这就需要在数据操作前对所操作的对象加锁,然后在操作完成之后释放。进程在操作加锁的数据时会产生阻塞,直到其他进程完成任务后,再继续执行自身的代码。
使用java.util.concurrent包里的对象来实现同步任务是可以的,不过较常用的是使用synchronized关键词。它可以作为关键词来修饰方法,那么对象方法会以对象自身作为锁,类方法会以它所在的类作为锁。当某锁因为因为某个进程的使用处于locked状态时,其他进程调用要求同样的锁的方法时就会发生阻塞,直到先前的方法调用完成。通常在Java的类中数据成员是私有的,然后通过公开的方法来使用数据。如果一个方法是非同步的,那么它运行的前后它说使用的数据将可能被同时执行的另一个自己或者同类的方法所修改,在一些场合这种不一致是会造成功能上的错误的。有时会需要获得一个成员的最新状态,则需要使用volatile修饰符。
除了用来修饰方法,synchronized也可以作为语句使用仅用来保护需要保护的代码。在一段同步的代码中,它可能因为某些条件不满足希望暂停执行。它可以释放锁让其他和它同步的方法可以被调用,并在适当的时候通知它可以尝试继续执行。为实现这样的模型,Java的在Object对象上为我们定义了wait和notifyAll方法。当一个线程在调用某方法遇到wait时,它会阻塞并释放锁,直到有其他进程调用了包含notifyAll的方法时再重新争取锁并执行。这样便实现了多线程调用同步方法当中,实现阻塞与否的移交以达成协作的目的。这也有些像把有待执行的代码放到一个方法列队中供其他方法调用,不过这里使用的锁的机制是让有待执行的方法阻塞,而其他的方法的任务仅仅是相当于通知阻塞的进程而不是这个列队中的方法的执行者。

H
为了编写数据结构的重用,Java提供了Collection框架。它和C++中的STL一样,定义了容器和迭代的概念。这样使得算法和结构之间建立了接口上的抽象,让同样的操作能够以同样的界面去用使用到它满足它应用的数据结构上。既可以直接使用Java提供的相关的实现,也为用户的扩充带来了方便。用户可以直接使用Collection实现自己的算法,也可以编写Collection类来执行已有的算法,或者以此为基础增加双方面的扩充。
在Java中对Collection的使用是从接口和实现两方面考虑,接口提供了容器的用法,而实现则提供了可实际工作的对象。和C++中运用泛型和模板来实现容器与迭代的不同,Java不是通过静态多态让某个因为提供了某些方法而能做怎样的使用那样的“窄”界面,而是从Collection这个能提供Iterator对象(通过iterator方法)的“肥”界面进行实现,并让不能实现的方法抛出UnsupportedOperationException异常。此外,出于对用途的限制并提供能多的方法,从Collection派生出的界面有Set(SortedSet)、Queue、List,以及方法名相同但无法直接派生的Map(SortedMap)。
对于容器的使用通常是通过容器的迭代器来使用的,它提供方法hasNext和next以遍历数据,还有一个可选实现的remove方法产生对容器的修改。其子界面ListIterator还提供了可选实现的set与add方法,以及Collection界面自身的add和remove(包括提供其他的冗余的函数)都可以用产生副作用。不过在一个迭代器使用容器的时候,该容器被其他的其他的方法修改会造成功能上的错误,Java有时会通过抛出异常来实现自我保护。由于容器实际上是储存了对象的引用,修改容器的成员和对某个成员的修改是不同的概念,有时为当前要操作的容器建立共有界面的副本也是种可行的做法。此外,有些容器需要对它所含的元素排序,它会要求其所含对象实现Comparable的compareTo方法,或者提供有compare方法的Comparator。String类出于不同的排序要求,对两种方式都有提供。
再具体一些来列举,界面Collection还提供有方法size、isEmpty、contains、toArray、~All,并确保可以迭代。子界面Set限定元素唯一(!equal),List增加的方法get、set、indexOf,Queue增加了增加peek、poll、offer了,Sorted的类型增加了first、last、subSet并限定了排序。对于容器的选择,需要从用途和实现两个方面考虑以获取更好的性能。Java中提供有实现HashSet、LinkedHashSet、treeSet、ArrayList、LinkedList、PriorityQueue、HashMap、LinkedHashMap、IdentityHashMap、WeakHashMap、treeMap。这些默认实现的名称已经表明的它们的工作方式了,如Linked使得修改变慢而遍历变快,没有多少选择的余地。不过在使用的时候,也就是为实现创建实例之后,依然是通过接口所提供的方法来进行操作。此外,和STL名称相同的若干类依然存在,它们是现有的Collection框架之前的实现,针对enum类型还有一组专门的容器。
对Collection创建副本,虽然它们有共有的元素,但已经是不同的容器对象了。而上面提及的subSet一类对Sorted方法皆适用的方法,而是为原容器创建一个视图,视图与容器之间会保持着同步的关系。Wrapper是另一种创建视图的方式,如Java提供有Unmodifiable和Checked。可能这些View在使用时并不常用,但确实是一种implement和extend之外定义类的使用的常用模式。

I
继续关于Collection框架。默认实现的算法在Collections和Arrays下面,如sort和binarySearch,以及其他一些如fill、copy、shuffle、reverseOrder、frequency等等有用的工具,外加提供一些特殊的如singleton、empty的容器对象。使用同步操作的话,可以使用SynchronizedWrapper,或者用java.util.concurrent里允许阻塞的特殊的列队实现。在实现自己的容器时通常从Abstract类派生而不是去直接实现接口,例如至少有size和iterator方法,一些方法会提供默认实现或抛出异常。
说到容器,就要来说一下泛型。C++的STL正如其名,正是在模板机制提供之后才被实现的。不过Java中情况特殊的是Collection是Java1.2的特性,而Generic是Java5中添加的内容。虽然现在通常容器和泛型总是同时使用的,但他们运行时是以不同的方式存在的。Java为了达到向后兼容的目的,对泛型采用了擦除机制。这也就是说在编译的时候,Java会为变量选择一个较抽象的类型,而在使用到具体的类型时插入Cast运算。例如对于没有指定类型参数的Collection容器,便是默认以Object类型为方法的参数。
Java有着比C++更为严格的类型机制,在使用着以类为可见性的同时,要求子类可以充当父类进行使用。这也就是说继承与实现不仅仅是一种机制上的,也是一种概念上的。它限定了子类若干行为,如不能缩小方法可见性,不能扩大抛出的异常,以使得这种严格的“is a”关系确保实现。旧Java中的Stack is a Vector便被认为是一个此方面的过失。
在泛型中,Java也同样维持着类的关系的存在。对于泛型类或泛型方法,从无类型参数的raw type,到提供了?、extends、super作为参数的类,到提供了具体的类提供的类,它们在概念上趋于严格。如果代码编译时存在对要求类型的范围有更严格的限定时,编译器会更具不同情况拒绝编译或者提示unchecked。我们称变量的类型是静态类型而对象的实际类型是动态类型,Java中的泛型就是一种在静态类型之中实现的机制,像“new List<String>[1]”这样直接依赖类型参数的语句由于擦除机制是不可行的。从使用上说,目前泛型是作为一种编译时的类型检查来看待的,仅仅主要运用在容器框架当中。

J
再顺便说一下Exception,也就是Java中的异常机制。在C++中异常是以一种对错误处理的抽象机制被添加到语言中的,它分离异常的产生者和异常的处理者使得代码更关注于自身的事情,也避免了返回值方式或全局变量方式易产生的疏忽。不过由于异常机制实现方式的差异,throw和try通常只在一个模块内部进行,也就是说在类库提交给外界的接口上异常是很难见到的。而在Java中,异常成为了程序逻辑的一个一个部分,和语言自身有着更加紧密的联系。
这里仅仅谈Exception,尽管他不是唯一Throwable的东西,它允许通过字符串的message来构造或者用initCause构造异常链。这里的重点是,Exception可以划分为RuntimeException和其他Exception两种,前者是unchecked的,不加捕获的Exception将会造成程序的终止。而后者,也就是checked的异常,是要求它所在的方法是写明throws它或者它的父类的,而调用的这样的方法也明确要求语句放在try块中不然不予编译。
在这里checked异常是作为程序的控制流程的一部分来看待的,也就是说一个函数的调用结果有两种。一种是正常结束返回它写明了所返回的类型,另一种结果则是抛出它写明的可能抛出的异常,它们都是方法运行允许的方式。
异常可以通过它所包含的信息来区分,也可以使用不同异常或建立异常间的继承关系。后者使得使得通过catch语句对不同的异常和某个异常的范围的判别变得简单而清晰。而finally语句中的代码会确保执行,即使有break和return也一样,常会和try前的某条语句配对使用,例如某个文件指针不为null便调用close方法。不过虽然异常也是一种程序的逻辑,但是在应该使用条件语句的时候,还是不要滥用异常。还有一个方便调试的assert语句,它不影响程序逻辑,默认未开启。

K
反射机制通过java.lang.reflect包使用,它为程序添加了在运行时使用类型信息的能力,例如实现一个简单的类型浏览器。不过反射作为一种机制提供,它只是被认为是可以用来做什么,除了权限外没有对它的行为有所限定。除非有明确目的,应该使用编译时代码中的Token来使用对象,而不是运行时的字符串来使用。
这里可以想到的两个反射的用法是动态载入和解析DSL,因为动态语言较依赖运行时,它们之间会见到一些相似的地方。
Java中为反射提供的类型有Class、Annotation、Modifier、Member(包括Field、Constructor、Method)、Arrays、Package,它们与语言中的类型直接对应,并提供了访问、修改和使用它们的方法,将一些语言层面的功能以方法调用的方式来实现。Class还有一个父类叫Type,它随着Java5泛型的添加包含了运行参数的信息。不过我们使用依然是以Class为基础开始的。我们可以使用对象的getClass方法、使用.class语法、通过Class.forName或者其他返回Class对象的操作来获得对象。
动态载入的目的是在编译时我们不能确定某个类时候存在,例如调用某个数据库后端。我们就需要使用类的名称作为字符串调用forName方法,它可能返回我们所需要的类也可能抛出ClassNotFoundException。通过获取类的Constructor对象,便能通过其newInstance方法来创建我们所需要的实例。如果连调用的方法也需要运行时确定时,可以通过字符串获得Method对象后调用其的invoke(this)方法。获得Annotation实例,或者根据名称找到可修改的方法也是可以的。关于Class的类型转换,有asSubclass和cast,可能会抛出ClassCastException。例如有语句“Class cls = Class.forName("java.lang.String").asSubclass(String.class);”,并有一个叫getName的方法与之对应。
其他方面的,Java持久化里用反射来调用私有方法,还有InvocationHandler和ClassLoader两个在特定场合很有应用价值的类。不过日常里和反射机制本身一样都不算常见,自己不大熟悉。再由于相关文档都有很详尽的说明,这里就暂且略过。

L
Java在内存管理上使用了垃圾收集机制,在JVM认为有必要的时候,它会自动执行System.gc()清理不再使用的对象。对象可以定义它的finalize方法供gc时执行,不过如果在程序退出前没有gc的话,这段代码也不会被运行到。这里使用这个概念会对Reference对象有特别的差异,如用于缓存或内存原因的动态加载。
对于单线程程序,main方法结束,整个程序也就结束了,并返回状态0。对于多线程程序,可以向其他线程发送interrupt消息,使得那个线程可以通过interrupted方法以及InterruptedException来接受到这个消息,来自行退出。不然Java会一直运行直到所有的用户进程运行完毕,除非某些进程setDaemon(true)或者System.exit被调用。其中后者也是Java中用来返回状态码的方式,而不同于C中int(main)。TimerTask都属于守护进程。在程序因为自身或外界的因素被要求退出时,有短暂的时间可以执行ShutdownHooks。还有另一种意外地使程序运行时退出的是运行时异常,由main或者run抛出而不会被try语句保护,此时可以为线程提供UncaughtExceptionHandler对象。出于调试目的,常使用异常的printStackTrace方法。

M
Java中的原始类型有boolean、char、byte、short、int、long、float、double,并将它们包装为Boolean、Character、Number(Byte、Short、Integer、Long、Double)、Void,并可以在使用时自动于两者之间转化。这些包装后的方法除了继承自Object的toString用于类型转化equals用于比较,还提供有果然类型相关的静态方法如valueOf用于构建parseType解析(两者是对应的)字符串,以及对象方法compareTo用于比较typeValue转回原生类型。一些基本的类型相关的方法,也由Number或Character类的静态方法提供。数学函数则由java.math,也包括高精足算法,浮点晕眩有实现无关的Strict模式。随机数用Math.random。时间相关的除了System.currentTimeMillis返回long,其他属于Date和Calendar对象,非原生类型。还有一个BitSet比位移操作使用起来直观一些。
Java字符串用String类,表示一个不可修改的字符序列。它提供的方法有charAt、length、subSequence、indexOf、startsWith、intern、replace、trim、toLowerCase、getBytes(这个涉及编码转换)。此外还有replaceFirst、split为使用正则表达式的提供了简便的方法。正则表达式由包java.util.regex提供,是一个风格类似于perl5的实现。其中包含Pattern和Pattern两个概念,前者用来compile表达式并对CharSequence使用split或matcher,后者提供matches、lookingAt、find并使用自身保存匹配的状态,其状态通过返回值以及start、end、group获得。正则表达式比写一串字符串相关算法要显得简单而清晰。
结合IO很实用的类有Formatter和Scanner,前者用来格式化输出,在printf中会自动调用,后者的功能正好相对应,通过迭代器风格的接口使用。自己合成字符串的话建议用StringBuilder,原先还有一个线程安全的StringBuffer。不同编码会统一以UTF-16的codePoint来实现,它是一个用于char的int类型值,也用于字符流。

N
javadoc是Java中用来从源码生成的文档的工具,清晰的文档可以便于理解代码的结构,也使得代码的复用的接口有了清晰的说明。
文档注释通过/** doc comment */插在所要标注的元素之前,每行以*开始,使用HTML语法。注释其中的第一段用于表示总述,后跟多个空格表示风格。多余空缺的注释,会默认按照一定的规则继承其父类的描述。还可以使用的元素有:@see、{@link}、{@linkPlain}、@param p、@return、@throws E、@exception E、@deprecated、@author、@version、@since、{@literal text}、{@code text}、{@value field}、@serial、@serialField、@serialData、{@inheritDoc}、{@docRoot}。方法名和类名之间用#分割。包的翁、当写在package-info.java中。
Annotation虽然也是多代码元素的一种描述,但常用的有CLASS和RUNTIME的区分。后者在运行时可以通过反射获得,获得一个@interface的实例。系统还提供了@Target、@Retention、@Deprecated、@Documented、@Inherited、@Override、@SuppressWarnings。例如使用@Override修饰的方法会在编译是检查没有应为参数的错误而对父类方法进行了overload。对Package也同样适用。

O
最后来罗列一些零散的内容,不是说它们不重要或没有值得说的东西,只是在这里不做展开了。
java.util中有Observer/Observable类型用于实现观察者模式。这是设计模式中常见的一种,通过维护一个关联对象的列表,用于对象间的协作。所以用派生是一种让双反接口相协调的办法。当然,模式只是一种类之间的结构方式,它在实现方式上并不唯一。
系统变量的获得可以使用例如System.getProperty("user.home");之类的语句。通过调用Runtime.exec可以获得一个Processes对象,然后以流的方式可以进行通讯。如果是使用Java类的话,可以通过java.security限定权限以保障安全。
使用ResourceBundle.getBundle可以载入ListResourceBundle对象或者.properties文件里描述的资源,不同语言的版本可以实现派生关系对通用版本进行修改。不同的语言版本会自动根据环境进行选择,这是Java中程序实现i18n的方式。
JavaBeans是Java中的一个复用组件,可实现BeanInfo或用反射生成。通过get和set使用一个serializable的有默认构造器的类。
嵌套类从Java1.1开始运行,不过编译器会用$分割符把它抹平。静态的嵌套类问题不大,仅相当于有了一个命名空间,以及一些访问权限上的规则。不然的话这个类存在于与外部类中或者存在于方法中或者是一个匿名类的话,它的实例需要保持一个对外部类示例的引用。这会用到如this.new这样不常见的语法,内部实例可以访问它外部示例的成员。
枚举Enum也是Java5新增的,它源自C语言。原本在Java是通过final static来实现枚举作用的,现在有了语法糖衣之后依然是这样实现的。和C一样用枚举表示数字当然可以,不过原本Java中还有一个用法习惯是枚举的成员是不同的对象,每个枚举元素可以有它的属性和方法。所以现在Enum也是作为一个抽象类使用,枚举元素可以利用方便的语言构造或者派生。
Java6里增加的特性让我印象深刻的是自带了JavaScript的支持,它可以和Java代码之间互相使用。JS作为一门标准化后的语言,这里用的是Mozilla的实现。动态语言的好处是类型属于值而变量不需要类型,类的接口是出于概念上约定而不必复杂的层次关系。
文件操作除了File***Stream,还有File类和RandomAccessFile类,用途和接口上更加传统一些。

P
内容还有一些其他可以说的,例如上面有没提到或者未提详细的地方,不过从品尝的想法和时间的允许的角度说,也只能挑选着内容来说了。下面这本书的目录会是一个更详细的提示列表,是关于Java的各种特性方面的:http://www.amazon.com/Java-TM-Programming-Language-4th/dp/0321349806 。
以后会后篇二,不过话题会有所不同,将谈到Java语言自身之外的更多的东西。那啥啥啥的,这篇的文字呢也就一个通常长度,当废话看,当游泳池看什么的都是可以的。
真的就到这行结束了,本文的下一行就真的什么都没有了,至少传说中的最后一行就是这一行了。
晚安!

关于Django和OrgMode的杂乱物

警告:此文是个坑!
* 前言
之前有帖子把Emacs和Python一起写,这次也把可以涉及到的一些内容写在一起了。
仅仅是写在一起而已,它们的内容在下面还是将区分开来放在不同的章节里的
* Django
** 什么是Django
已经很长时间没碰Django了,以下的内容算是回顾一下之前接触到的一些状况,仅是回顾而已不再深入。
** Apache上Django
这一段说的是Apache的共享主机上一个可行配置方案,是目前比较常见的部署环境了。
用VPS的话,在更大的权限下会有更好的方案,还是看Django文档吧,这里暂不做更多尝试。
个人参照了helionet.org上方案,并做了尝试。可以用fcgi或者mod_wsgi的方式。
Django文档中在howtodeployment一节里面有同样原理的说明。
** rewrite
在用户访问的路径下建立".htaccess"文件,权限为644。
这里要做的事情有两件,让静态文件文件可以直接被返回,让对Django页面的请求能够转发到我们编写的项目上。
#+BEGIN_EXAMPLE
RewriteEngine On
RewriteBase /
RewriteRule ^(media/.*)$ - [L]
RewriteRule ^(admin_media/.*)$ - [L]
RewriteRule ^(dispatch\.wsgi/.*)$ - [L]
RewriteRule ^(.*)$ project_subdirectory/dispatch.wsgi/$1 [QSA,PT,L]
#+END_EXAMPLE
这个文件根据自身的需要来写,以上仅仅是一个示例。
** wsgi
紧接上一段,建立文件dispatch.wsgi,并设置权限为755。
#+BEGIN_EXAMPLE
import os, sys
sys.path.insert(0,"/home/zsyweb/public_html/python-site/");
os.environ['DJANGO_SETTINGS_MODULE'] = 'project.settings'
os.environ['PYTHON_EGG_CACHE'] = '/home/your_cpanel_username/.python_egg_cache'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
#+END_EXAMPLE
django模块和我们的站点都是作为一个模块被import,随意要添加到"sys.path"中。
然后会有一个"environ['PATH_INFO']"字符串,它就是交给我们的urls.py匹配的部分。
该文件会被作为一个进程执行,并在被更新时自动重启。
** ……
在自己的home路径下建立目录".python_egg_cache",并设置权限为777。
上传Django模块,以及自己的项目,是它们都成为一个单独的目录,并保证父目录已添加到"sys.path"中。
在服务器上设置好数据库,然后执行"manage.py syncdb",即使无法使用shell也可以通过上传cgi脚本或执行call_command函数来解决。
如果使用Sqlite的话,要让它所在的目录具有可读写的权限,不然肯定有500错误。
** GAE上Django
目前Django程序是不能直接在GAE上执行,主要是由于ORM模块不能使用,导致依赖Model的部分需要以GAE提供的界面的来编写。
不过就目前而言,Django-nonrel是个很不错的解决办法,它为Django的ORM提供了NoSQL数据库的后端,其中就包括GAE。
目前觉得GAE还是不错的,注册时只需要用手机收取一下注册码,然后就可以免费建立若干应用了。
** GAE
需要安装Python2.5和GAE SDK1.3.5,我那时候故意选择这个版本的,因为they work。
不知到好来的GAE又更新了什么,当时安装了新版本却反而不能正常工作。
之前用Google的CLI工具也出现过最新版不如之前某些版本稳定的状况。
** Django-nonrel
*** 获取
去它的网站下载若干压缩包回来,它们就是下面烹饪过程中的食材。
其中的django-testapp解出来就是我们的项目目录,可以看到我们熟悉的manage.py文件在里面。
其他的文件是我们的项目import入我们项目的模块。根据Python的规则,一个模块就是一个有__init__.py的目录,目录名作为模块名使用。
就目前DN提供的模块而言,我们解开它们应该得到的是:
- <project>/django
- <project>/djangotoolbox
- <project>/dbindexer
- <project>/djangoappengine
不过因为GAE对文件数有限制,以上文件肯定是已经超过了。所以接下来的可算步骤成立必须要做的事情:
- 把django模块(就上上面列出的那个目录)打包为django.zip,放到名为"zip-packages"的目录下。
这个目录已经添加到"sys.path"中了,我们的Django App或者其他模块也可以以同样的方式处理。
不过DN的其他几个模块就不要动了,它们和我们项目结合较紧,会在较早的时候被import到。
*** 使用
**** ORM
DN最大的作用,同时也是比较通常Django应用最需要的注意的地方即是它的ORM。在NoSQL数据库上,数据是也对象的形式保存的,对象可以包含可若干属性,对象的属性可以不存在,也可以建立索引。但是在关系型数据上的JOIN查询却是不提供的,同时在数据库事务中如何保持数据的一致性上也有些许区别。
那么也就是说包含JOIN的查询,aggregates,select_reated目前都是不可以使用的。此外many-to-many和transactions也不能使用。
当然不能使用并不是说我们在用到这些特性的时候就达到不了我们需要的结果,而只是实现方式上不那么直接。一是需要自己再多去实现一些代码,一是会有性能上的损失。
例如对于join查询,可以增加查询的次数,将一些判断从SQL中移到Python中来。值得注意的是在迭代中使用查询是一件很恐怖的性能损耗,即使必须用到这样的方法来实现某写功能,一定要设置好缓存,并额外设置计划任务对缓存进行更新。
对于M2M关系,也需要手工建立"through"用到表,也就是有两个ForeignKey指向要建立关联的两个对象。
然后通过重写save以及相关的方法或者建立signal来确保这个表示Reletionship的表中记录能够在正确的时候被创建和删除。
事务方面,GAE提供了额外的支持,暂时和Django的事物模块没有关系,相关的内容在GAE的文档中。
**** Mangae
使用的格式是"manage.py <command>",命令shell、createsuperuser、syncdb都可以使用。
需要注意的是这些命令是对本地GAE数据库操作的,在NoSQL中虽然表依旧存在,但是字段是属于数据而不是表的,在对表的字段作出修改的时候,原有的数据项依然存在数据库中。
GAE的开发环境是把数据库以文件的形式存在本地硬盘上的,可以手工删除这个database文件。
此外"manage.py deploy"会上传整个项目,命令中加了"romote"如"manage.py remote createsuperuser"那么它所操作的数据库就是服务器上的数据了,它和本地的开发环境是想独立的。
静态文静也是同样的上传,然后需要在GAE的文件app.yaml中做关于路径定向的设置。
最然直接访问Django的Admin页面,但是在表和superuser建立之后,就可以正常工作了,所以不小心看到了500的错误的时候,不要慌乱了手脚哦。
**** GAE的限制
坑,涉及数据查询和运行时间
** Django的Style
*** 倾向
之前社团里说来建议一个站点,于是我就拿Django来写了写,不过最后还是中断了。
因为觉得使用现成的Php应用可以减少维护成本,其次也没有人去推动这个社团站点的设想。
再者当代码越来越多的使用,如何去掌控这个规模也是自己的短处,频繁的重构只使得结构变得脆弱,而新代码使得代码越来越难以修改。
所以,这里有必要重新回顾一些最Django的方式:
Django的出现是英国一个新闻站点的需要,它们需要以一个快速固定的方式,为新闻事件建立站点。
在这一个过程中,需要尽可能的实现功能的重用,此外还有整个开发流程的重用。
在Django中Model和URL是站点构建的一个出发点,Model部分将决定我们我们做要呈现的数据是什么,而URL部分是站点提供给用户的一个接口。
然后,另两个需要同时考虑到的重要要素是View和Template,View表明了站点呈现到用户面前的是什么,而Template将表示这种呈现将是以何种的效果。
可以以Restful的URL通过Generic views实现对Model的操作,也可以让Model和URl配合让Generic views能够正确的展现出来。
*** 避免
话说自己之前对Model过于重视了,觉得数据是站点的全部内容,其他的部分之不过是对数据的表达。
直到看了未来的Django1.3中View是可以mixin了,才发觉原先想法中的不足。
有时一个站点的构建也可以是从View开始的,人们是先意识到一个站点是要呈现什么,然后再去实现构建它的数据模型的。
当然,我只是说Django的使用去保持一种量产的态度,而不要太过调整它的结构(仅是说使用,Django的开发不在此限制之内)。
例如自己的一个不够如意的尝试就是利用ContentType机制,也就是相当如Java中反射加Python中的鸭子类型的一类东西那种不会用的时候很容易滥用的东西。
让整个站点的代码通过派生共用抽象模型,全部变成模型的一部分。
再加上metaclass等动态机制,让model提供一堆protected virtual的东西,而把CURD的View以及Form等东西全部抽象掉。
虽然这种修改我原以为会让之后代码修改变得简单,不过之际中,严格依照Django提供的结构把一个Model和它涉及到的View啦Form啦什么的都分开来写一遍。
这里仅仅是分开来写一遍而已,Django已经是提供的声明式的语法而且还有一段时间的向后兼容时间。
保持代码的基础以一个简洁稳定的方式,对于之后代码量大后的维护,才是可行的方式。
特别是通过建立自己的template tags,使得每个view只需要负责他所负责的数据,或许即使是像国内站点首页那样的庞然大物,也可以参照类似的方式来增加代码的灵活性。

** 回顾
居然这段打算说的被前面说掉了,大意就是这段时间没写Django代码过了。也没为自己写个博客程序,应为觉得还是blogspot省心。而且就搭建开发环境上来说还是php省心,最简单的情况是存一个php文件就能运行。想随手一个Django应用的话,则一下子就要面对许多需要涉及和不需要涉及的事情,MVC啦ORM啦如何去部署啦都是一下子都会考虑到的问题。当这种复杂性不是瞬间需要的时候,反而是对随手写几行代码这种行为的一种困扰。
不过,相比于Php门槛低应用多的优势,使用Django还是有他可以胜任的场合的。例如Django所要求的结构可以降低自行编写的站点的复杂度,有一个直接完整的学习过程,而且拿Python写算法的话也要相比而言等方便一些。
学习成本和使用成本,如果绘制成为曲线的话,它们陡缓的场合是不同的。
** 代码片段
这里内容并没有什么特定的内容,仅作为一个堆放而已。
#+BEGIN_SRC python
- url: /static
static_dir: static

from django.contrib.auth.models import User
user = User.objects.create_user('root', 'email', 'pass')
user.is_staff = True
user.save()

User.objects.create_superuser('root', 'e@mail.com', 'pass')

def profile_create(**kwargs):
if kwargs['created']:
profile = UserProfile.get_or_create(user=kwargs['instance'])
profile.save();
post_save.connect(profile_create, sender=User)

class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)

#+END_SRC
user singal
django-registration
Nonrel-search
各种各样的缓存,只能指定的方式使用乖哦能
#+BEGIN_SRC emacs-lisp
点对点
#+END_SRC
#+BEGIN_EXAMPLE
点对点
#+END_EXAMPLE
abspath(
* org-mode
** 什么是org-mode
在emacs中,Org-Mode已经是自带的了,它已经是我开Emacs的主要用途了。
输入"M-x org-mode <RET>"就可以进入,用info可以查看它们的使用说明,文件名后缀.org。
自己主要拿它来写文档用,比如说这篇就是在org-mode里面写的,之前有一篇小说也是。
包括上文提到的那个站点项目,也是用org-mode来描述想法和记录进程的。
首先呢,建议阅读[[http://orgmode.org/orgguide.pdf][OrgGuide]]这份文档,它是对info手册的摘要,对系统地去了解一下org-mode还是很有帮助的。其中对org-mode的定义是:
: Org is a mode for keeping notes, maintaining TODO lists, and doing project planning with a fast and effective plain-text system. It is also an authoring and publishing system.
这段话概括了Org-Mode的功能,不过再接下来的文字里所要关注的,不是去列举org-mode的功能或者单纯的学习操作,而去寻找若干实际的应用场合,来看看Org-Mode是如何帮助我们完成特定的任务的。
享受Org-mode带来的文本显示与展示效果,使用它提供的种种功能,以及简化输入用的快捷键。
关于它所拥有的各种,本文无意去全部涉及或概括。至于使用上的创意则完全是看各自发挥了。
通过org-mode提供的格式,让其中文本语义在编辑中展现出来。
出于习惯,为节约编写时间,除非有特别的要专门要求,以下内容将从略,所以会以意义不甚明了的状况。
** Emacs的使用
仅当热身用,仅涉及光标移动什么的,对键盘的亲切感是下文展开的基础,因为org-mode的使用就是就是和文本大交道的。
那么,来尝试一个最基础的小问题吧:
1) 创建文件demo.txt
2) 输入"I don't like Emacs."
3) 保存一下
4) 把文本中的"don't"去掉
注意,这时候的光标在行末,编辑后也要把光标移到行末哦。
那么,我们可以有多上中手段来达成这个需且呢:
+ 用<Left>键向左移动光标
+ 用C-b来向左移动光标
+ 先用M-b移动到句首光标
+ 先用C-a来移动到行首
+ 用C-s来根据字符定位光标
+ 用鼠标来移动点击要移动的地方
+ 用bs建向左删除字符
+ 用delete向右删除字符
+ 用C-d向右删除字符
+ 用M-d向右删除单词
+ 用M-%把单词替换为空白
+ 用鼠标拖选单词后删除
+ 在单词一端M-@标记,在另一端C-w剪切
+ 在行首C-k删除行后重输
+ 最后C-移到行末
+ 或者M->移到文末
当然这里这样列举纯粹为了娱乐,况且这些确实是最基本的一些操作。
而且都是很有规律的按键,想必各位都已经对此出于机械反应了吧。
M-空格也很有用
** Outline
这个记号"*"星号,就是用来建立文本层次的,顶格写,后更一个空格。"*"连写则表示是一个子层次。
在层次下面还可以补充的使用"-"、"+"、"*"、"1."、"1)"建立列表,有前后空格,用缩进表示子层次,可"::"后跟描述。
注意要避免发生和前一种方式的混淆,前者是用来组织文档结构的方式。
然后来看一组快捷键:
#+BEGIN_EXAMPLE
折叠显示
TAB Subtree cycling,
S-TAB and C-u TAB Global cycling,
C-u C-u C-u TAB Show all, including drawers.
C-c C-x b 在新缓冲区内显示树
光标的移动
C-c C-n Next heading,
C-c C-p Previous heading,
C-c C-f Next heading same level,
C-c C-b Previous heading same level,
C-c C-u Backward to higher level heading.
编辑
M-RET 创建同层次同类型新项目
M-S-RET 见下文TodoList部分
M-LEFT/RIGHT 改变当前项目的层次
M-S-LEFT/RIGHT 改变项目层次,包括子项目
M-LEFT/M-RIGHT 移动当前项目位置
M-S-UP/DOWN 自动项目位置,包括子项目
C-c C-w 移动项目往某个位置
C-x n s/w 显示当前全部/项目
C-c - 或 S-方向键 改变项目状态
S-<Tab> 改变项目层次
C-c ^ 排序项目列表
C-c * list和tree之间转换
匹配
C-c / sparse tree
#+END_EXAMPLE
在Emacs中Outline也可以做单独的主模式或副模式使用。
有时后为了美观,会使用org-indent-mode。手工调用或#+STARTUP: indent都可以。
此外C-c C-c是个很有常用的按键,其功嫩根据场合,且没有破坏作用。
M-<TAB> 是多种场合下用来补全的快捷键。
这里sparse tree只是+-|&的条件查询
** Rich Text
*** Footnotes
个人比较喜欢的方式是用来做生成文档是用的页脚注释
: [fn:: This is the inline definition of this footnote]
不过一般还是在文本中"C-c C-x f"分开写,然后用利用OM的自动的链接功能,如
: [1] [fn:name]
*** Hyperlinks
用来实现HTML中的超级链接的功能
[[link][description]]
: [[link][description]]
其中[description]可以省略
可用的快捷键有:
: C-c C-l 创建/编辑链接
: C-c C-o 打开链接
: C-c & 返回跳转之前的位置
此外关于link的格式
#+BEGIN_EXAMPLE
[[My Target]] 或自动寻找文档内文本的位置
# <<My Target>> 用注释添加目标
[[*My Targets]] 仅查找项目
<<<My Target>>> 会自动创建指向它的链接
文档内章节引用的指向文字,也通过这样的机制来实现。
也可跨文件查找
[[file:~/code/main.c::255]]
[[file:~/xx.org::My Target]]
[[file:~/xx.org::*My Target]]
[[file:~/xx.org::/regexp/]]
使用URL
file: mailto: 或 http:// 来用不同协议指向本地或远程地址
可用此在插入图像
对于同类链接,可以用#+LINK简写
#+END_EXAMPLE
链接可以直接在Org-Mode中使用,或者在到处为其他格式时有特别的效果。
*** Markup
这一节说说富文本的标记
#+BEGIN_EXAMPLE
默认只用"\\"才表示换行,
不过这个可以该设定为"\n",也就是按实际文本的换行来。

有若干按格式引用文本的话,有方法
用 #+BEGIN_*** 和 #+END_*** 的形式可以
VERSE、QUOTE、CENTER

文字样式
*bold* 粗体
/italic/ 斜体
_underlined_ 下划线
`=code=' 代码
`~verbatim~' 字面的
`+strike-through+' 删除线

水平线用单独一行至少5个"-----"

可以在文本中添加注释
顶格写# 不顶格写#+
用COMMENT开始文本树的标题
结合BEGIN块使用,可以用M-<Tab>方便输入
快捷键 C-c ; 也是照常工作

在文本中插入示例使用
名为EXAMPLE的BEGIN块,或者": "(冒号+空格)开头
插入源代码用SRC块,之后跟参数如"#+BEGIN_SRC emacs-lisp"
编辑源码的快捷键有 C-c ' 和 C-c l
代码块提供参数支持格式或文本内引用的功能
使用参数-t则在HTML中以TextArea来显示

可以插入其他文件中的文本
如 #+INCLUDE: "~/.emacs" src emacs-lisp
这里的第二个参数是块名SRC,按键"C-c '"依然可用
可选参数 “:prefix1 " + " :prefix " " ”为引入内容添加前缀

可以在文本中使用宏
定义: #+MACRO: name replacement text $1, $2 are arguments
插入: {{{name(arg1,arg2)}}}
#+END_EXAMPLE
这段用来一个EXAMPLE块来展示,不过依然建议只在需要的时候再使用,以是文档结构清晰。
*** Tex & LaTex
此项功能用来在文本中插入特殊符号和数学公式,也或者为导出PDF格式做特别的标记。

特殊符号以"\"开始,可以使用补全,如
: \alpha \beta \gamma
将得到 \alpha \beta \gamma
它在HTML和LaTex输出中都可以使用,将分别得到
: &alpha; $\alpha$
{}符号依照Tex做结尾可选的间隔符用

上下标使用类似Tex的语法
: x^{2} a_{1} 10^30
得到 x^{2} a_{1} 10^30

对于特殊输入,都可以用\符号来转回原意

数学公式可以用dvipng程序转为图片,例如供HTML使用
LaTex片段使用\begin或直接插入公式片段
#+BEGIN_EXAMPLE
\begin{equation} % arbitrary environments,
x=\sqrt{b} % even tables, figures
\end{equation} % etc

If $a^2=b$ and \( b=2 \), then the solution must be
either $$ a=+\sqrt{2} $$ or \[ a=-\sqrt{2} \].
(setq org-export-with-LaTeX-fragments t)
#+END_EXAMPLE
可以在编辑模式中`C-c C-x C-l'插入预览效果,`C-c C-c'恢复文本显示
注意$里面不可以有多余的空格,不然直接作为文本识别了。

使用CDLaTeX minor mode可以得到类似AUCTeX的编辑便捷
*** Include
使用 #+INCLUDE: "file.org" 可以引入另一个文本的内容
也可以以块的形式引入,或者 “:prefix " "”为每行添加前缀
: #+INCLUDE: "~/.emacs" src emacs-lisp
也有宏替换的功能
: #+MACRO: name replacement text $1, $2 are arguments
在文本中可以使用】
: {{{name(arg1,arg2)}}}
: {{{title}}}
这里的title是由 #+TITLE: 指定的
*** Image
插入图像的功能,通常用在到处为其他格式时嵌入显示。
关于如何将org文件导出为其他格式的文本,将在下一节里说明。
#+BEGIN_EXAMPLE
插入表格
#+CAPTION: This is the caption for the next table (or link)
#+LABEL: tbl:basic-data
| ... | ...|
|-----|----|

#+CAPTION: This is the caption for the next figure link (or table)
#+LABEL: fig:SED-HR4049
[[./img/a.jpg]]
#+END_EXAMPLE
这里的CAPTION是插入内容的说明文字,而LABEL则是用于文本中的引用。
*** Source Code
导出或执行代码。
** Export & Publish
*** Org2____
功能集中在 "C-c C-e"按键下面,如果此时按键停留一段时间,屏幕上会给出进一步按键的提示。
输入`C-c C-e t'将给当前的文本插入一段输出选项的模板,对此模板的修改是接下来将org文件转换为其他格式的基础,因为很难保证默认的转换规则对当前文本适用。
至于为什么要org-mode的文件转换为其他格式,这个问题是...
如果一点这样的需要也没有的话,那么以下的内容就是在废话了,所以就暂且默认一下吧。
1. org-mode方便文本的编写与管理
2. 有时我们需要在不同场合使用不同分发格式
3. org-mode格式并不适合发布
不过,编写与发布其实是一个连贯的过程,org-mode的使用是一个流程中的一部分。
而不是像这里分出123在列举某一方面的优势和不足的。
*** Option
关于选项模板中的的 #OPTIONS选项,因为不像其他选项那样可以按照名称辨别,所以这里转一下说明:
#BEGIN_EXAMPLE
H: set the number of headline levels for export
num: turn on/off section-numbers
toc: turn on/off table of contents, or set level limit (integer)
\n: turn on/off line-break-preservation
@: turn on/off quoted HTML tags
:: turn on/off fixed-width sections
|: turn on/off tables
^: turn on/off TeX-like syntax for sub- and superscripts. If
you write "^:{}", `a_{b}' will be interpreted, but
the simple `a_b' will be left as it is.
-: turn on/off conversion of special strings.
f: turn on/off footnotes like this[1].
todo: turn on/off inclusion of TODO keywords into exported text
pri: turn on/off priority cookies
tags: turn on/off inclusion of tags, may also be `not-in-toc'
<: turn on/off inclusion of any time/date stamps like DEADLINES
*: turn on/off emphasized text (bold, italic, underlined)
TeX: turn on/off simple TeX macros in plain text
LaTeX: turn on/off LaTeX fragments
skip: turn on/off skipping the text before the first heading
author: turn on/off inclusion of author name/email into exported file
creator: turn on/off inclusion of creator info into exported file
timestamp: turn on/off inclusion creation time into exported file
d: turn on/off inclusion of drawers
#+END_EXAMPLE
关于LaTeX的数学公式的导出方式,在HTML文件中还有更具体的选项,需要参考具体的org-mode版本。
*** ___2what
个人是转为HTML较常用些,转为Text或者LaTeX也是可以的,org-mode还支持其他一些格式。
针对要转为的格式,可以添加一些直接的额外的标记。它们通用的形式如下:
#BEGIN_EXAMPLE
插入单行 #+DOCBOOK:
插入块 #+BEGIN_DOCBOOK
对标记插入 #+ATTR_DOCBOOK
#+END_EXAMPLE
具体一些什么的,之后再来根据遇到的一些实际的情况来补充,所以暂且略过。
*** HTML
1. CSS样式调整
2. JS交互界面
参见http://orgmode.org/Changes.html
*** Latex
1. 配合XeLaTeX使用
2. 关于中文的设置
*** Org
关于直接发布org-mode格式的一些说明
*** Project
到处项目的作用是将一组org文件转换为一个HTML站点
命令依然是以"C-c C-e"开始,不过还是需要提前来做一些配置。
** TodoList
*** GTD
前面貌似说到过,本文的目的并不是关于org怎么用,或者或来说明org-mode有哪些功能。
本文的目的是,如何用org-mode来达成我们需要的一些任务,也就是说想写成CookBook一样的东西。
当然,这只是对文本进行考虑的一个出发点,至于做到没做到就有时另一回事情了。
而且出于自私的想法,写着写着来跑题聊一些轻松的话题也是很有趣的事情。
甚至有时为了写着轻松,留了很多类似“请自行参考文档”一类的话,而让文本的内容常常莫名其妙。
然后,我还会有一个借口,叫什么“本文的目的是导读,而不是作为参考重点用的笔记。”
其实吧,本文也确实不是笔记。笔记什么的是学习时候的记录,用来之后做参考的。
而本文呢,出发点是对自己的使用感受做一下总结,看看对目前自己比较实用的有哪些用法。
好了,org-mode的那么多功能自己也还不都能用好,说成总结是有点牵强了,因为自己对om的使用也毕竟只算个开始。
不过话说会这里的关注点,本文只是恰巧是用om写关于om的话题,更多的机会还是用om写和om无关的东西。
只是om有功能可以让自己的事情完成的更方便一些,对om使用的增加只是会是om的存在感变得降低。
这样来说的话,对org-mode的使用就根本不是在一个学习om的过程之中了。
对于一个工具的使用,会存在两个方面的因素,一是自己能做什么,一是工具能做什么。
虽然这两者必须依赖于自己用工具做了什么,才能够显示出双方的意义,而且双方并不都是永恒不变的东西。
课本上面那种“普遍真理”一类的话,这里不想拿出来说了,因为它总是想用我遇到的例子来说明它的正确性,而不是关注到自己面前所处理的问题上。

这节是叫GTD来着,看来我跑题了。其实这也是一个自私的想法,因为对于一篇没人看的文字,我只好以满足自己的YY来作为优先原则。
话说什么叫GTD呢,它是一种时间管理的方法,很多PIM软件如果知道GTD方面的理论的话,会用起来顺手一些。
自己用的熟悉而是也是唯一的一款PIM软件是MS的OutLook,这是因为我手机上自带的关系。
虽然在新闻讨论中它并不常见,但是它确实功能成熟,而且确实很好用。
它包括了若干组件,比如邮件,日历,任务,便签,联系人,还有其他什么我不清楚的东西。
话说据说其实org-mode还有点像OneNote来着,因为都可以用于记笔记,手机上ON是还可以手写和录音。

不过自己用Org-Mode的话,还是以它的笔记功能为主,对日程方面的很多功能还不熟悉,而且暂时也觉得没有去熟悉它们的必要和动力。
所以这节换题虽然是如何以orgmode去实现任务列表功能,不过还是将继续上面几节的话题的方向。
*** TodoItem & CheckBox
按键 M-S-RET 用来将下方插入,headline对应todo headline,list对应checkbox。
headline可以通过"C-c C-t"或者"S-RIGHT/LEFT"在unmarked和TODO以及DONE状态之间转换,用来标记代办事项。
用"C-c /"来sparse tree时可以显示依照TODO状态来显示部分条目,树状条目的状态存在依赖关系,即子项目的状态是父项目的一部分。
有#+TODO:用于对状态的设定,S-UP/DOWN可以用来改变条目优先级状态。
CheckBox是list前包含[ ]或[x],父条目后包含[%][/]来统计状态。
其中后者对headline也适用,其状态会根据子条目的TODO状态自动改变。
用C-c C-c来改变其选中状态。关于细节在M-S-RET之后就会很明了的。
*** Tags
用:tag:标在headline后面,以方面整理,或添加属性。
相关的按键是"C-c C-c",可以":key1:key2:"使用多个tags。
Properties以k-v的形式实现类似的功能。
*** Dates & Times
"C-c ./!"插入,用S-LEFT/RIGHT/UP/DOWN改变光标位置的状态。
也支持时间范围(A--B)和离散的时间点(如每个...),可插入在headline后与om的其他机制配合。
*** Dict
在org-mode中使用字典,虽然这不是OM自己的功能,不过有实用价值。
** Calendar
出来MS的OutLook,Xfce的Orage也是自己很喜欢的日程类软件,OM的Mobile暂时无条件享用。
不过就目前的自己而言更多还是依赖纸和笔的传统方式,对GTD软件的使用还不大,以下部分从略。
*** Deadlines and scheduling
C-c C-d Insert ‘DEADLINE’
C-c C-s Insert ‘SCHEDULED’
配合TODO有Progress Logging
*** Capture - Refile - Archive
若干特定显示模式,或者项目的管理
其中C-c C-w Refile在文件内移动条目位置还是很有用的功能。
*** Agenda Views
建立文件列表来进行日程管理,以及相应的界面。
可以结合着使用全局的TODO列表。
用"C-c ["加入当前文件
*** Attachment
C-c C-a
** Spreadsheet
在org-mode可以插入表格,或者充当电子表格使用
*** Tbl
在菜单中有Tbl,其中列举了会用到的功能。如果菜单让你费解的话,请看下面的文字。虽然在接下来的使用中没有用到菜单,不过它们涉及的内容是一致的。
*** Tables
| ID | Key | Value |
|----+-------+--------|
| 1 | apple | Red |
| 2 | pear | Yellow |
| 3 | | |
#+TBLFM: $1=0
表格以|开始行或者|-做分割,之后TAB或RET键就可以被识别,C-c-c表示刷新。
表格的行宽会被自动根据内容的长度被调整。
#BEGIN_EXAMPLE
`C-c |' 创建或转化为表格
`M-<left>/<right>' 移动栏
`M-S-<left>' 删除当前栏
`M-S-<right>' 在左边插入栏
`M-<up>/<down>' 移动列
`M-S-<up>' 删除当前列
`M-S-<down>' 在上方插入列
`C-c -/<RET>' 在下方插入水平线
`C-c ^' 排序区域
`C-c C-x M-w' 区域复制
`C-c +' 获得栏的和
`S-<RET>' 自动插入栏
#+END_EXAMPLE
标题<N>指定显示宽度,用`C-c `'编辑。
列有水平线,栏则通过
#BEGIN_EXAMPLE
| / | <> | < | | > | < | > |
| / | < | | | < | |

#+END_EXAMPLE
有minor mode叫orgtbl-mode在其他mode中使用。
还可以结合gnuplot-mode使用。
*** Excel
这里是说那om充当Excel的部分功能,虽然统计分析什么的om并不可用。
引用单元格使用@ROW$COLUMN以及$2..$7,可以绝对数值或+-的相对数值。
然后可结合Calc或Lisp的表达式使用。
:=对当前单元格输入表达式,=为栏输入。
`C-u C-c C-c' `C-u C-u C-c C-c' 执行计算更新
** End
说明一下,虽然本文有好多处是说什么待写啦暂略啦,不过如果有补充的话会另开文的,所以对上面含糊的内容就不必要有期待了。
额,发现一文,比我写得好:
http://linuxtoy.org/archives/emacs-org-mode.html。

* 文本信息 :noexport:
** 笔记
todolist 思维导航 GTD 笔记 发布 日历 xiangmu xelatex
#+TITLE: Django和Org-Mode的若干
#+AUTHOR: ee.zsy
#+EMAIL: ee.zsy@163.com
#+DATE: 2010-11-10 星期三
#+DESCRIPTION:
#+KEYWORDS: django org-mode emacs python
#+LANGUAGE: zh_CN
#+OPTIONS: H:3 num:t toc:t \n:t @:t ::t |:t ^:t -:t f:t *:t <:t
#+OPTIONS: TeX:t LaTeX:nil skip:nil d:nil todo:t pri:nil tags:not-in-toc
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
#+EXPORT_SELECT_TAGS: export
#+EXPORT_EXCLUDE_TAGS: noexport
#+LINK_UP:
#+LINK_HOME:

2010年10月26日星期二

Shell脚本

关于Linux Shell以及脚本应用的简单索引与指南用贴


本文是关于shell脚本的一篇索引,很是简略
内容很是含糊,仅作为记录,更多请参阅其他文档
它们用起来都是很实用的东西的说,属于Tools的范畴
是用熟练了反而能体会到它到来的好处的东西
这类话题相关入门的书籍和文章还是算较容易接触到的


目录结构

Linux默认的目录结构如下
/
/bin
/sbin
/etc
/dev
/dev/null
/dev/random
/dev/urandom
/home
/mnt
/lib
/root
/tmp
/usr
/usr/bin
/usr/include
/usr/lib
/usr/local
/var
/var/log
/var/mail
/var/spool
/var/tmp
每个目录有固定的用途,这里不详述


man和info

用来查看帮助文档
还有额外的文档在/usr/share/doc/


sh - shell

shell的作用是执行程序和管理回话
bash是现在最常用的shell实现,在debian中还有一个较简单的dash
shell有部分命令是Builtin的,例如cd、echo、exit,还有job相关的jobs、fg、bg(kill在bash也算了),管道(这个不算命令来着,文件和流也是shell的重要部分)
在一个session中可以执行多个进程且可以嵌套,回话终止时会结束它的子进程除非用nohup(还有at、cron可用,ps或top可看到进程)
除了Emacs的快捷键可用,还有用来发送信号的信号的按键:C-c 终止、C-z 挂起、C-d 退出

shell也可以写成脚本来执行,将命令行写为文本文件保存
开头#!/bin/sh接下来是脚本内容,然后添加可执行权限chmod +x filename
脚本中可以使用变量,列表,环境变量,执行命令,执行表达式,使用test判断,使用管道,添加控制流程,定义函数,处理参数
脚本也可以用其他的解释语言来写,对于调用者来说是一致的

存在若干默认的启动脚本。


ed - text editor

ed通过相互的输入命令来编辑文本行
命令的格式是[address [,address]]command[parameters]
编辑显示存取文本都需要输入相应的命令来执行


sed - stream editor for filtering and transforming text

sed常和管道一起用在shell脚本中
其工作是以行为单位的,下面是一个文本替换的例子,也可打印删除什么的
sed -e 's/old/new/g' inputFileName > outputFileName
用;分号构成语句序列可以跳转,单行语句(包括块语句)前后构成条件关系,有剪切粘贴


awk - a pattern scanning and text processing language

常用的实现是mawk,debian里默认装的这个
命令的格式是pattern { action statements }
也可包含BEGIN块来设置行匹配的选项,或者print一些东西。
语法接近于c和sh,可用于将文本数据生成数据报告
作为单行命令行或者写成脚本都是可以的方式


其他

对于文本操作还用若干命令可以使用:
tee - read from standard input and write to standard output and files
cat - concatenate files and print on the standard output
grep - print lines matching a pattern
iconv - Convert encoding of given files from one encoding to another

ls可以用来在目录中查找文件,此外还有:
find - search for files in a directory hierarchy
locate - find files by name


链接

http://www.debian.org/doc/manuals/debian-reference/ch-program.zh-cn.html
http://en.wikipedia.org/wiki/Shell_script

2010年10月22日星期五

实用的原型继承

现实生活中的原型继承

时间匆忙,此帖就略,来介绍一下原型继承是什么东西。


* Self

Self语言,是一种基于原型的面向对象程序设计语言,以原型简化了类的概念,让类在视觉上直观。
虽然其研究已经停滞,但是在动态语言的实现优化上有应用。
相关信息在一份名为self: the power of simplicity的paper有明了的说明。

此文详述了原型继承的优点(简化实现,增加对象灵活性),以及原型继承和类继承的比较,这里不再转述。
其中关键的两个概念是slot和parent:
在self中所有对对象的使用都是通过消息来进行的,对象的数据成员的读写通过命名slots。
例如对象有属性x,则x消息用于读取,x:消息用于写入,只读消息则只有读槽没有写槽。
槽是一个方法,也是Lisp中的一个Closure。
当对象消息所指向的槽不存在时,则指向其parent对象,对象间的数据共享也通过parent的solts进行。
从简化实现的角度说,对象方法的局部环境也可以用一个子类来实现,用parent指向对象的环境。


* 类对象系统

C++中的Class是对Struct的扩展,数据和虚函数表属于对象,而方法函数属于类。
如果一个方法不是虚函数的话,它将在编译的时候转化为一个函数的调用。
smalltalk的对象机制则有些差别,它对方法的查找是在运行时动态的,详情我不清楚。
c++所选择的机制是从运行时性能的角度来考虑的。


* 设计模式

在《设计模式》一书中,PROTOTYPE是作为一种对象创建模式来讲解的。
可以用于以原型的克隆来减少类的数目,且提供在运行时控制对象原型的能力。
在C++这样的类对象系统中使用原型继承的方法并不唯一,在实现的时候需要考虑的是对象的管理方式(是否需要存放在一个关联数组中),如何去定义对象的clone操作(就是C++的复制构造,有复制深浅和如何初始化的问题),以及指向原型对象的指针可以用来托管操作(this->proto->clone())。
因为实现方式上有很大的自由度,这里不做代码举例,重点在对象的名为proto的指针和名为clone的方法,前者类型为指向自身类型的指针,后者返回和对象自己同样的类型。
当然,这里也不排除我对文本的内容的某些片面理解。

class A{
private:
    A* proto;
public:
    A clone(){
        return A(*this)
    }
}
这里的代码只是用来体现代码结构,并没有完善实现细节,例如完善默认构造和复制构造。
对象成员中可以包含函数指针,且方法调用中有一个隐含的this指针,这为自行对机制的扩种提供的方便,只是缺少一些语法的方便(用操作符作DSL?)。


* JavaScript

依照ECMA-262的1.3和1.5文档第4.2.1节的描述,js中提供原型机制实现了对对象继承和数据共享的支持。
在Javascript中函数也是对象的一种,所以对象中不会像类继承中和其他成员不区分对待,函数作为方法时可以通过this访问使用的对象。
构造器constructor是一种特殊的对象Object,它是一个函数(有[[Call]]方法)且拥有"prototype"(原型)属性(默认是每个函数对象都会自动创建该属性,以便我们往其中添加添加属性,当然也可以指向已有对象)。
因为构造器是一个函数,它可以按照一个函数来定义它的功能(例如Date(2009,11)返回一个字符串)。
而如果通过new表达式使用constructor,则会创建新的对象(例如new Date(2009,11)返回一个Date对象),并以该对象为变量this去执行构造函数(可选的是如果构造函数有返回对象则new返回这个对象)。
其创建的对象的属性prototype指向其构造其的prototype,在查询对象成员的时候如果缺少则系统就会转向查询其prototype所指向的对象。
函数对象在创建时在原型属性中默认会有指向自身的constructor属性,可方便于执行clone操作。
操作符instanceof调用对象的[[HasInstance]]的方法,其实现是依据对象的prototype实行来判断。
Type和对象将自动在需要的时候被执行,类似与Java的Box/unBox机制,例如从StringType到StringObject的转换。
对象的prototype属性可以在运行时改变,这是原型机制在动态性的一个体现。

实例代码(没有测试):
Point=function(x,y){
    this.x=x;
    this.y=y
}
Point.prototype.move=function(x,y){
this.x+=x;
this.y+=y;
}
使用:
var p=new Point(4,5)
p.move(3,6)
以上是目前较常见的使用方式,在第三方库往往会再做包装。
值得注意的是,这里的构造器在来的创建中不是必须的,它只是js语言本身提供的一种方便的机制,并和其他一些识别对象的函数保持供用的信息。


* Lua

Lua是一种和Javascript很相似的语言。
它对象是Table,并提供了metatable机制,对象实现的方式交给了使用者指定。

例如,可以实现为(未测试):
Point = {
    new = function(self, x, y)
        local object = { x=x, y=y }
        setmetatable(object, self)
        self.__index = self
        return object
    end,
    move = function(self,x,y)
        self.x, self.y = self.x+x, self.y+y
    end,
}
然后使用
local p=Point:new(4,5)
p:move(5,-2)
这里虽然用了类似于原型的机制,但实现上Point是起的类的作用,用来创建实例和负责类的方法。


* Python

虽然Python是使用的Class机制,不过由于其动态的,在实现上和原型机制有类似的地方。
类和实例都处于对象:类有属性__dict__和__bases__,前者是方法和类属性所在的空间,后者是基类的列表;实例是有调用class对象创建,有属性__dict__和__class__,前者是用于存储类的属性,后者指向创建它的类。
如果没有方法截获属性查询的语法,实例成员的查找会现在实例中查找然后再到它的类中,也就是说只有类可以做原型使用(Python在它的class机制中会保护一点),而类的原型则是其继承机制的实现方式。
这样的限制为在Python中导入C++类带来方便,而如果仅有原型机制则为实现的一致性带来的障碍。

试验代码:
class A:
    pass
class B:
    pass
a=A()
a.__class__=B
print a
虽然这段代码看不出明了的价值,但是它是能够工作的,最后的输出为%lt;__main__.B instance$gt;。
class也是对象,它是type对象的实例,也可以用type(name, bases, dict)的语法来创建。
并同时也实现了元类,即类的类这一递归的概念,派生出type的子类来进行类的创建。

不过虽然Python允许在运行时给对象添加属性包括使用lamdba,但是对象方法仍然需要在类中定义。
如果需要self那样的原型机制,一个可行的方式是使用@classmethod,代码示例如下:
class A:
    v=5
    pass
class B(A):
    @classmethod
    def f(cls):
        print cls.v
即把class直接作为一个对象来使用,用继承来表示原型。
或者,用模块和import *,效果类似。


* 单实例类

原型机制的一个好处是用来实现单实例类,例如用来实现对一个虚拟世界的抽象。
代码请自行补脑。


* Scheme

Scheme给使用者相当大的灵活性,这让我们可以实现自己的对象与消息机制,一个成熟的参考是CLOS。
不过简单的一个对象可以写成:
(define (num value)
(lambda (method)
    (cond
     ((eq? method 'print) (display value) (newline))
     ((eq? method 'next) (num (+ value 1)))
     (else (error "method missing"))
     )
    )
)
对原型的查找实在else语句的那一步执行。


* 原型继承的使用

用来读取富含逻辑的数据


* 多分派

这是题外话,关于C++的Oberride机制。
在C++中,方法可以是virtual的,也就是说调用对象方法所执行的代码是运行时动态判断的。
而目前的overload机制却完全是在编译时静态决定的,也就是说当参数是派生类时,C++依然只按照传入指针变量的类型而不是指向对象的类型来判断所调用的函数。
用if语句判断类型是一种办法,目前一个较通常的解决双分派办法是visitor模式。
再一次virtual,以arg->m(*this)来使用。


* 链接

Self - the power of simplicity:
http://selflanguage.org/
Standard ECMA-262
http://www.ecma-international.org/publications/standards/Ecma-262.htm
一个javascript的仿self环境
http://adamspitz.com/Lively-Outliners/example.xhtml
A Minimal Javascript Object Environment
http://minijoe.com/


* 附以前一段试验代码

虽然这段代码没用用到原型继承,不过有值得这方面的尝试。
此外,在lua用可以用自定函数来构造table,而不一定只用默认的{}语法。
--[[
演示
ee.zsy
2010.1
]]

--BASE
function table.pos(t,sth)
    for i,v in ipairs(t) do
        if v==sth then
            --say("i="..i)
            return i
        end
    end
    return 0
end
function table.has(t,sth)
    return (table.pos(t,sth)>0)
end
function table.del(t,sth)

end
function table.add(t,sth)
    table.insert(t,sth)
end
--UI
function put(sth)
    print(sth)
end
function say(sth)
    print(sth)
    io.read()
end
function key()
    return tonumber(io.read())
end
function cls()
    os.execute("cls")
end
function select(sth)
    if sth.quest then
        print(sth.quest) end
    for i,v in ipairs(sth) do
        print(i.."."..v)
    end
    local c=key()
    return c
end

--SAVE
save={

place="",
bag={}

}
--DATA
map={

home={
    name="家",
    goto={"tree"},
    has={"she"},
    run=function(self)

    end
    },
tree={
    name="森林",
    goto={"home"},
    has={},
    run=function(self)
        local tree={}
        self.goto={"home","shop"}
        self.has={}
        if not table.has(save.bag,"card") then
            self.has={"card"}
        end
        --table.insert(self.goto,"shop")
    end
    },
shop={
    name="商店",
    goto={"home","tree"},
    has={},
    run=function(self)

    --return k==1 and "home" or k==2 and "tree" or nil
    end
    }
    
}
obj={

she={
    name="女友",
    type="human",
    run=function(self)
        say("你好啊")
        --select{"df","df","df"}
    end,
    catch=function(self,o)
        say("什么东西?")
        if o==obj.card then
            say("好啦,我早就认识你了")
            return true
        end
        return false
    end
    },
card={
    name="身份证",
    type="thing",
    run=function(self)    
        return false
    end,
    use=function(self,obj)
        say("你出示了"..self.name)
        return true
    end,
    take=function(self)
        table.add(save.bag,"card")
        return true
    end
    
    }
    
}



--VIEW
function move(plc)
    put("这里通往:")
    for i,v in ipairs(plc.goto) do
        put(i.."."..map[v].name)
    end
    local c=key()
    local o=map[plc.goto[c]]
    if o~=nil then
        save.place=o
        return true
    end
    return false
end
function search(plc)
    put("这里有:")
    for i,v in ipairs(plc.has) do
        put(i.."."..obj[v].name)
    end
    local c=key()
    local o=obj[plc.has[c]]
    if o~=nil then
        o:run()
        
        if o.take and o:take() then
            say("你得到了"..o.name)
        end
        return true
    end
    return false
end
function bag(plc)
    put("你要使用:")
    for i,v in ipairs(save.bag) do
        put(i.."."..obj[v].name)
    end
    local c=key()
    local o=obj[save.bag[c]]
    if o~=nil then
        if o:run() then
            return true
        end
        if o.use then
            put("对什么使用呢?")
            for i,v in ipairs(plc.has) do
                put(i.."."..obj[v].name)
            end
            local c=key()
            local oo=obj[plc.has[c]]
            if oo then
                o:use(oo)
                if oo.catch then oo:catch(o) end
            return true
            end
            return false
        end
    end
    return false
end
function show(plc)
    cls()
    plc:run()
    while 1 do
        cls()
        put("==你在==\n"..plc.name)
        local s=select{quest="你的操作","移动","调查","背包"}
        if s==1 then
            if move(plc) then
                return
            end
        elseif s==2 then
            if search(plc) then
                return
            end
        elseif s==3 then
            if bag(plc) then
                return
            end
        end
        say("你未操作")
    end
end

function main()
    save.place=map.home
    while 1 do
        show(save.place)
    end
end

main()
另一种写法是用switch语句。

这里,包括整篇文字的目的,是表达一下抽象(v.-%gt;n.)。


继承类型的选择

最后,两种继承机制有其侧重,与应用的场合。
在系统设计上,类继承有比较成熟的方法,且比原型机制更容易抽象。
原型继承则较直观地用来变现数据,用代码体现出数据中可执行的方面。

2010年10月15日星期五

日记[101010]

出游·远足


这个周日的时候,班里进行了一趟秋游。一早的时候的,吃完早点,在校门口乘上了公交车,向着目的地的方向驶去。
首先的行程是登山。登山就和爬楼梯一样,在日常看来是件很普普通通的事情。不过想起来自己也曾把登山视作过一种有特别意味的象征,将日常生活的感受与之类比,并寄希望于在其中能让感受变得明了和清晰。
出于节约开支的打算,行程是从山后上山的,下山也是从山后下的。水泥的山路与台阶起伏在山间,从一个山头延伸向另一个山头,连接其若干标志性的建筑。途中也走到了较粗燥的石块路上,上山显得陡峭,下山则显得地滑。不过在同行的协助之下,并无太大危险。
带着略有饥饿的身子,接下在的行程是在山下的另一头吃烧烤。几人围着在一个石桌上,隔着锡纸,用火红的木炭加热着食物。清澈粘稠的食用油涂在暗红色的冷肉上,伴着沾着的孜然发出的香味,在食物的上下翻弄之中,发出滋滋的声响。
手边一瓶度数不高的啤酒,倾斜向面前的塑料杯,看着又一次被灌注的液体和升腾起的泡沫。就这烧烤着,吃着,喝着啤酒,吹着山底的凉风,感受着一阵阵升腾起的烟雾和热度。渐渐地,自己手边的这个啤酒瓶里已由满,变得半空,变得空荡荡的。离开了面前食物的废墟,然后再在一旁吹了会儿风,便踏上和来的方式一个样的,回程的道路。

这就算一篇简单的日记吧。记录了一次出游,虽然只是如流水一样的简单记录了一下行程,其中并无蕴含着特别的想法。
说到想法,现在的自己已经不喜欢在留下过多的想法了,就的凭借自己胡乱的思考仅仅是在积累着往日的浅薄。于是,变得倾向于在文字之中仅留下最简单的记录,记录着自己的视角上看到的或许真实的一切,记录着曾经的经历,以及一些不必对其有任何怀疑的存在。
这便是成长吧,否定着过去的自己,又希望过去有某种永恒可以永远的传递下去。

下面来写个小故事,是在出游归来后的时候想到的:
故事发生在战场之上,两个邻国因为争执正发生着激烈的战争。有一行人,大约也就十来人。出于RP问题,被困在了一个被包围的山林里。突围就有被歼灭的危险,什么都不做就是在这深山之中等死,所以绝望在他们的心中日渐萌芽生长。
行军的生活资源已近面临缺乏,而周围的局势未见任何好转的倾向,他们决定,必须开始最后的尝试了。故事的主角便是在他们大家的推选之下,担当这次突围行动的指挥。大家推选他是因为我们的主角有勇气能够担当其这份责任。
他们推选指挥的目的在于,如果鲁莽的行动或者零散的行动,大家都会损失惨重,甚至无一幸存。我们的主角也相信,在自己和大家共同的努力之下,大家都能够为大家实现一份守护。
故事便在这种团结之中开始了,后来在混乱之中结束了。大家的行动还是变得单独起来,利用着他们,增加着自己活下去的可能。不过这不算一个坏的结局,虽然大多数人不幸死去,还是有一两个人幸运的战士活力下来。
我们故事的主角并没有那么幸运,在进行着一个大家讨论出的危险但或许可行行动的时候,发觉队友并没有更上,然后独自受敌而遇难了。
临死的时候,他仿佛听到了队友的嘲笑——
在绝望的时候,在面临着生存与否这个问题的时候,已经没有人会挂念别人是否活下了。在惊慌了内心里,只会去在意自己的存在,在意只要有幸运者的存在,便去抢夺这种可能。

好了故事说完了,虽然这是出于自己的价值判断来讲述的一个故事,但是在保持着一个旁观者视角的时候,也是自身的视角混杂在这个故事之中了。故事讲完了,也仅仅是讲述完了而已。当自己再想进一步地对这个故事中的人物评价,并得到一个完整而一致的判断的时候,我发现自己已经不知再如何说下去了。觉得再说下去,就是让自己变得单纯,变得天真,变得⑨一样。而以为只有矛盾,只有混沌,只有犹豫,才能把自己眼前的世界还原为一个他应该成为的方式。
作为一篇日记,我是认为这里的文字应该一次写完的。不过出于内容的篇幅的考虑,一次来写显得有些量大。其实分次来写也未尝不可,不利的地方是会多花些日子,有利的地方时可以把这篇日记写完。而且在如何在这里的文字继续往下写这个问题上,需要的是判断,而不是犹豫。

于是,现在在过了久久的时间之后,再把原先想到的一些内容,继续往下写。有些想法,它的存在是因为在曾经的时刻存在过,在日后并不会去怀疑其存在,而是其中是曾希望发现的东西在过后变成想遗忘的东西,去抛弃其中的缺憾。那么,过去的时刻,给将来的时刻留下的,会是如何的经历呢?下面将把若干内容,以简略的方式来说一说。
先说学校的新图书馆,是这学期新开放的。当我初次进入了它的大门的时候,第一反应是去找守则规范一类的东西——也就是使用说明一样的东西,因为新馆的借书方式和之前的其他各馆略有不同。结果是没有找到,于是内心感到了微微的茫然。
守则一类的东西是个有趣的东西,在大一入学的时候学校还让图书馆的工作人员来专门开课指导我们图书馆的使用。这种课的作用也仅仅是了解了图书馆的使用规则,而具体的借书操作仍是要去图书馆实际操作时候,才会对整个流程有所熟悉。往往在经历一些不适时候,就会对书的查找借阅感到得心应手。
守则就是这样一种约束人的东西。但是同时,守则也是对借阅者的守护,因为守则的存在可以让借阅者有了可依照的流程。借阅者行动的重点是去找到需要的书籍,而整个流程的方式有了一个可依靠的方式,反而是以约束来减少了整个借阅行为中的负担的事情。而现在的情况的是,面对了一个新的图书馆,原本的守则之类的东西已经不再完全使用,原本的守则赋予的守护已经变成了陈破的存在,借阅行为已经是一件需要重新去面对的事情。
以上来看,自己是将周围环境简单的变化给复杂化了。因为改变的事情无事不可不在发生,不论是自身的周围的环境,以及自身对待外界的态度。
一次自己在图书馆里坐着,看着来来往往的人群。每当听着门口的报警装备想起来的时候,内心就会觉得这是一件可笑的事情——去笑话新生作出了各种各样的可笑的失误。然后,又在这独自地压抑在内心的嘲笑中,去笑自己的胆怯——觉得已经应该变得成熟,不会去犯幼稚的错误,却没做出任何有价值,或许并不完满的尝试。

出游前一天的一堂课上,老师忽然放下课本,想聊天一样地随意的说了起来,是说那天的课堂有点显得沉闷。当时自己听了有些在意,因为自己也是对此有所想法,所以想听听老师对此是如何的看法。不过另一个更让自己在意的原因是,在一个让人失落的课堂上,老师是需要去设法的回避自己的想法的。
课堂在一个稳固的模式中进行着——投影打出的幻灯一页一页切换着,一个平稳的不带感情的声音重复着上面的文字,就这样仿佛了一年又一年;课本被随意翻弄着,偶尔有起落的笔记。下课铃快想了,老师和学生合上书离开教室;一学期过去了,老师和学生变得像陌生一样。一切显得平静,一切显得波澜不惊。
当然,这是一种悲观的想法,一种悲观地去不发现其中任何的改变的可能。去明白别人耀眼的成绩不属于自己,是自己即使努力也不一定会得到的东西。去认识在自己所处的环境有着极为有限的教育资源,去知道适应远比改变要简单的多。去放低自己的满足的限度,去明白大学是用来虚度时光的,只要有一个毕业有一份工作,然后能够活下去就行了。去觉得别人的生活看起来值得羡慕,却不一定有自己生活的方式那样惬意地幸福。
以前的带我们的班的老师说过这样一句话,当然也不排除随着时间的而自己对其片面地加深了曲解:“我们学校要培养学生的自卑感,这样一来可以便于管理,一来学生容易随意找份工作。”这句话有可以赞同的地方,因为人要学会谦逊,因为我是这个学校的一员,但是同时也后值得不满的地方,因为这是出于一个管理者的立场而不是我所处在的一个学生的视角。后来这位老师升职了,这一定意义上证实了他的信条存在的价值。并且个人的不满不会对别人有任何的好处,而对自己也不会发掘到有价值的东西。这是一种值得欣赏的直白,也是一种去轻烟弥散于空气不可探寻的痕迹。

学习是人处于世界的一种权利,就像认为人人生而平等,造物主赋予他们若干不可让与的权利,其中包括生存权、自由权和追求幸福的权利是不言而喻的真理一样。每个人有接受教育的权利,有通过他所学到的知识去创造价值获得收益的权利,并可以理想地去认为一个成绩的取得是限于他的能力和愿望。
学习的过程是一个知识与直接积累的过程,是为了让一个人可以胜任更复杂的工作。在学习中一个人获得了他面对问题可以凭借的素材,获得了面对问题的自信。这种自信是他的经验和已获得的成绩,而也是这种自己让他可以在面对问题的时候去积极地寻找解决的方法。
当然以上的想法又将事情变得有些理想化,因为当生存都是一个问题的时候,大学的存在悲观地意义上讲就是一个逃避就业的工具,去吸取着父母辛劳的工资,去虚度四年的时光。
这里又将话题转向了悲观的方式,这是因为现实就是一个悲观的存在吗?人总被接受教育去面对眼前的路,哪怕是让人成为一个有追求的人,或者变成一个只要能能够得过且过生存下去的人。可以不论是悲观,还是空想,都同样是一种人对自己的保护机制吧。
用自己能够做到的事情去否定自己能够做到的事情,然后借此去放弃能够获得的东西,然后小心的自己的已有的东西在消失。就是这样的一种半借口半现实地将一切怪罪在自身和环境上面。
学习是一个判断力被积累的过程,学习不是让老师成为了一种用来依靠的东西。让别人的讲述和判断去代替自己的判断,而让自己觉得自己的任何想法都是无知和缺乏自信的。而当别人只是无表情的灌输着文字,在自己复述不能时候,感到深深地无望。学习的是出于知识自身,而非依附于人的存在。
学习学到的东西有很多:一可称为事实,它是对知识判断和运用的基础;一可称为推断,它是事实间的关联,由已知向未知的推进;一可成为经验,它是曾经对事实和推断的应用,让新场合下的应用可以达到一个从无到有的过程。这便是一个学习的过程,一个因为需要存在而存在的东西,而不是悲观视为单纯人生的磨练。
由次也可以推论出一些关于练习和考试的的想法。考试是一个向自己向别人证实自己的方式。考试是对学习过程的一个检验,以让学习的过程可以获得期望的结果。考试为学习建立的一个目标,而明确的方向可以让学习的过程变得果断而作出坚定的付出。考试是为学习阶段的肯定,是对学习的付出的一种回应,这也可以让可有面对实际的问题的时候,可以果断地去运用自己学到的知识。同样的,练习也可视为是种短期的考试,它作用于学习过程中的一个阶段。值得区别的是,练习也可作为一种学习的方式,用以模拟将会遇到的问题来提升思维的活跃度,来作为一个思维积累与之后可以利用的过程,是一个对学习的补充与调剂。总之,练习与考试都是以它们不同的方式,成为整个学习过程中拥有着积极作用的事物。此外,在练习与考试的竞争与协作中,也有利于整体(包括个人,以及自己)的水平的提高。
写着写着,自己的设想是尽可能直白的文字去展示能够被认同的要素。虽然在一些视角上一些显得片面,显得固执的想法,但是能够自圆其说是已经能够作为这些文字存在的的一个限度了。

不过继续往下写,也有让人犹豫的地方,至少如果单纯的以文字堆砌的方式让内容继续下去的话,就不会去思考一个尺度让内容指引向某一个特定的方向。例如正确的方向,当然过于追求的字面上的正确似乎并不存在,那么就是一个对自己有利的方向?
本篇当初自己定其为日记,字面意思,就是记录一下当天的事情和想法。本篇的开始也是,又那天的登山远足开始,不过因为想写的内容有些多,如果一天来写完的话,内容有些多,写起来也会吃力一些。
可以分开写,是因为对要写的内容有完整的打算。虽然是若干显得散乱的话题,可以只要一件件按照次序记录下来,便也可算作是一片日记的内容吧。不过,对记录事情而言是可以,对记录想法却有了难度。自己可以去回忆曾经历过的事情,却不可以再回到那时的感受上。从现在的角度看,就是那个登山之后的那份心情,那份在山间的空气过滤之后周围一些仿佛变得简单的心情。有时不知以那份信心和清晰的感觉去经历事情是对是错,因为它们只是那么短暂的一刻,然后就又回到的一片以河为围栏的校园中,去怀疑自己以及身边一切可以怀疑的事情。
让文字就这么写下来,随意地在键盘上敲打着,不去思考自己预计要写的内容,不去思考自己是否在记录着自己真实的想法,不去思考自己或别人在之后看到这些内容的时候会如何看待这些东西。文字的内容就这么被敲击下来,以其中看似可以连贯的逻辑,以其中看似可以说得通的解释,以其中字数堆积让那个txt文件的体积变得越来越大,以越来越多的文字去这篇里原先打算写下的所谓收尾的文字。以至于难以辨别,这是让本日记的内容得以继续,还是只是以另一种方式去覆盖掉曾经留下的可笑的想法与经历。

月初的时候,说到大一的弟弟的专业并不理想时候,家里的长辈是鼓励他好好学习,去达成转专业的条件。这可以算是他目前学习的努力的意义和一个方向把。这其中和我自己类似的地方是,我也曾认为自己的专业不够称心,而学校在转专业上仅是非常有限的选择。再者现在已是大三,已经两年的时间过去了,也就是说我是不会考虑到他所面对的一个机遇和选择。有一次和班里的老师说到班里的一个同学,他是到了一个有些类似的专业去了,老师当时就表现出很有抵制的样子,大意是选择什么的是一件会让人份心的事情,认为这对于我或许并非是一个好的东西。于是对于专业的被认识就往两个方面展开了。一是说人要学会适应,人要学会生存,能把大学结束然后有个工作,就以前完满了,其他个人的想法就是多余的了。另一种说法是,环境工程其实可以一个不错的专业,在这一行里以后还是有很有前途的地方的,从事一个专业要学会喜欢这个行业。这两种想法没有什么好否定的地方,认为它们是在曲解或修饰什么。就像去简单地认为自己如果去进去了另一个专业,是否就能处理的比现在这个专业好一样这个问题。
以自己经历的失败,去幻想未经历的事情中的成功,是一种对当前现实的逃避。因为一个人能够经历的事情是有限的,而他永远会有未经历的事情,那么以此为借口就可能落得一个一事无成的下场。但是从另一方面说,在当前经历的失败中,去幻想可能出现的最好的未来,也未必就是一件合理的想法。这就让一切变成了一场关于付出的赌博,认为只要付出,越陷入其中的付出,就会有像彩票一样奇迹发生。
这里把选择划分为了两种,虽然自己也没有写明白这两种分别是什么东西。只是重点落在二这个数字上,然后各自想法中可以否定的东西拿出来否定一下。同样的,下面的内容中,也可以这两种想法中挑选一些可以用来肯定一下的内容。
首先是关于对自己的了解,关于自己的长处。他们在面对问题的时候不是多余的东西,是在解决问题中值得凭借的东西。学习什么的,不是以别人的方式去应对,然后重复着别人会遇到的困难,然后再加上自己的不足。那样只会让一个还不错的结果,变成很难不错的结果。
其次是关于选择,对于作出的选择就需要有承担这份选择的责任。而且即使是放弃选择,也并不是意味着就可以放弃其中的责任。
而且,学习不好大学学环工,大学学习不好以后一辈子干环工。这句话虽然写出来有些过分,但是在某种意义上是自己的现实,来所谓对自己的激励也未尝不错。况且自己也并不是讨厌这个专业,只是不擅长,外加一份放弃选择地心态去面对它而已。
由已经经历的挫折去不顾一切地怀疑未来的经历,把未来的经历中的不完满视为一个永远的诅咒,觉得不幸什么的就是注定的,所以认为应为安份与现状,把已经接纳下的事情作为是心目中的最好的选择。这种方式的保护,去以放弃的方式来避免遇到的困难。去认为风险与成功都只是属于别人的东西。这段的想法,也很难说就是正确的,去吧一切的非现实去归纳为不现实,并由此保留仅存的现实。
那么对于人生的选择,是消极或积极,是逃避或责任,这都只是字面的上差异而已。探究其中的相似点,都是在向某个方向度过时日而已。正确与否也不是并借现在面对屏幕的空想就可以得出一个用来安慰自己的结论的。因为在自己小小的空间里,也往往会把想法引向一个片面错误的方向。然后放弃那些显得多余的意义。
那么,这最后的几段文字可以概括为什么呢,是安慰自己的方式给自己鼓劲?
结论是——
把握机遇不等于逃避现实。

至于,这个登山远足后的结论有什么作用,我不知道。
日记就这样,错别字什么就暂不再改了。
况其自己有事情正反着说都说成合理的的习惯,以上内容不必当真。
至于看见废话或是逻辑混乱的地方,知道算我的日记习惯就可以了。
Fri Oct 2010

====
日记这东西是用来记忆,还是用来遗忘的呢?

2010年10月13日星期三

同步用贴

当前使用的Chrome扩展
不定期与本地Chrome状态同步一下,仅表示当前有安装,并不表示推荐或其他。
Linux下依然使用Firefox,midori候补。K-meleon则作为Windows下的候补。
#20101013创建页面

AdSweep
An online ad-removal tool for your favorite web browser.

After the Deadline
Check spelling, style, and grammar in your browser

Chromium Wheel Smooth Scroller
Fully customizable smooth scroller for chrome. A port of Yet Another Smooth Scrolling on Firefox.

Classic Games!
All the classic games that you love to play all assembled in one place on your browser!

Development and Coding Search
Quickly searches programming language and API reference documentation.

Edit with Emacs
Allow user to edit web-page textareas with Emacs (and other editors).

Firebug Lite for Google Chrome
Firebug Lite for Google Chrome, supported by the Firebug Working Group.

Google Dictionary (by Google)
View definitions easily as you browse the web.

Imgur the world
Easy way to put online images on imgur. Open an image click on the extension button and get the imgur link directly in clipboard.

iReader
View news stories and other articles in a very easy to read, clutter-free, scrollable display.

jQuery Shell
Allows jQuery command extension in current page context.

Lazarus: Form Recovery
Autosaves everything you type into textareas so you can easily recover from form-killing timeouts, crashes and network errors.

Note Anywhere
with this ext, you can make notes on any web page, any position. when you open that page again, the notes get loaded automaticly.

Notepad
Save your notes / ideas...forever. Uses HTML5's localStorage.

OnlineDict
Click the word in any page, and the translation will show up.

Proxy Switchy!
Manage and switch between multiple proxies quickly and easily.

ProxyPy Web Proxy
You can load the web page through a fast/stable web proxy. Power by ProxyPy Engine (http://proxypy.org)

Python Shell
A python shell in your browser.

RSS Subscription Extension(由 Google 提供)
在您的工具栏上添加一键订阅。

SingleFile
SingleFile helps you to archive a complete page into a single HTML file

Speed Dial
Speed Dial for Chrome - replace Chrome new tab with your predefined visual bookmarks.

Textarea Code Formatter
Gives textareas basic code formatting abilities found in modern IDE.

TinEye Reverse Image Search
This is the official TinEye Chrome extension. Find out where an image came from, how it's used, or find higher resolution versions.

translate
Zoned word translation

Web Developer
Adds a toolbar button with various web developer tools. The official port of the Web Developer extension for Firefox.

Window Resizer
Resize browser window to emulate various screen resolutions

Youdao Dictionary (by Gecko) (已停用)
用有道的api查词,有音标以及读音(zh-en and en-zh dictionary by using youdao dict api

维基百科伴侣 - 迷你维基浏览器
维基百科用户必备扩展。功能全面:保存您最近的维基查询记录,多语种,后退/前进等等!

迅雷、快车、旋风专用链自动破解
自动把页面里的迅雷,快车Flashget,旋风链接替换为真实地址,使用你自己喜欢的下载方式来下载.

2010年10月1日星期五

Python的Web服务器

Python的Web服务器

* Socket

基本的概念见 http://en.wikipedia.org/wiki/Berkeley_sockets

先拿Netcat做点试验:
输入“nc g.cn 80”命令,然后输入“GET / HTTP/1.0”,然后敲几个回车。
这样会通过使用TCP协议得到HTTP协议下网页返回的内容。
然后输入“nc -l 8080 | nc g.cn 80”,实现了一个简单的转发,-l是listen的意思。

常用到的API是:
socket() 创建Socket对象
bind() 服务器端与地址绑定
listen() 服务器端开始监听TCP连接
connect() 客户端建立TCP连接
accept() 服务器端接受并建立TCP连接
send() recv() 用于数据IO
close() 关闭Socket对象
select() 用于实现非阻塞Socket
poll()
这里Socket的协议通常是PF_INET表示IPv4,类型有:
SOCK_STREAM如TCP
SOCK_DGRAM如UDP
以及基本的SOCK_RAW

用Python代码表示就是:
#+BEGIN_SRC python
#服务端
import socket            
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 8080))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
    data = conn.recv(1024)
    if not data: break
    conn.send(data)
conn.close()
#+END_SRC
#+BEGIN_SRC python
#客户端
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('localhost', 8080))
s.send('Hello, world')
data = s.recv(1024)
s.close()
print 'Received', repr(data)
#+END_SRC
UDP客户端则没有connect而使用sendto来发送数据。

使用“infds,outfds,errfds = select.select([s,],[],[],5)”会阻塞,直到s有数据传入,以实现非阻塞的网络服务器。


* 内置

使用cgi模块和CGIHTTPServer模块便实现了简单的网络应用及服务器了,不过这不是这里的话题。
感觉Java有界面这个东西会使得一些概念变得清晰,在实现接口知道了要提供的东西,Python的模块提供使用方式似乎有很大的多样化。
这里要说的是SocketServer模块里内容,涉及TCPServer和UDPServer通过实现自己的Handler类来处理数据。
在实现异步服务器上有ForkingMixIn和ThreadingMixIn用于实现多进程。
或者用asyncore和基于它的asynchat模块来使用Socket,通过实现handle_*对Socket的不同阶段进行处理,不过没有实现更抽象的东西。
SocketServer.TCPServer有子类叫HTTPServer,实现有handle()方法将HTTP请求的消息发送发到do_*()方法上。
通过Python模块自身就是用Python编写的,仅在最底层上或出于性能考虑才会和Python的实现直接接触。
#+BEGIN_SRC python
import SocketServer, BaseHTTPServer
class server(SocketServer.ThreadingMixIn,BaseHTTPServer.HTTPServer):
    pass
class handler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_GET(self):
        print self.path
        self.wfile.write("Hello World")
httpd = server(('',8000), handler)
while 1:
    httpd.handle_request()
#+END_SRC

不过对于Web框架来说通常的做法是实现WSGI这个接口。

叫底层的SocketServer是,直接贴Py文档中的一段代码了:
#+BEGIN_SRC python
import SocketServer

class MyTCPHandler(SocketServer.BaseRequestHandler):
    """
    The RequestHandler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        print "%s wrote:" % self.client_address[0]
        print self.data
        # just send back the same data, but upper-cased
        self.request.send(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

    # Create the server, binding to localhost on port 9999
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)

    # Activate the server; this will keep running until you
    # interrupt the program with Ctrl-C
    server.serve_forever()
#+END_SRC


* CherryPy

CherryPy是一个Python的面向对象的Http框架(这里使用了CherryPy3)。
先来看一段代码,最常见的HelloWorld程序:
#+BEGIN_SRC python
import cherrypy
class Main(object):
    @cherrypy.expose
    def index(self):
        return "Hello World!"
cherrypy.quickstart(Main())
#+END_SRC
看起来和Web.py的HelloWorld很像,而且它们都是用于Web站点的开发。
不过之间的区别还是明显的:Web.py涵盖了模板引擎和数据库绑定(虽然都功能比较基本)需要部署到服务器上;而Cherrypy虽然可以按照TurboGears样子整合其他组件成为一个完整的Web开发框架,但是其自身是一个多线程的Web服务器。

对于Cherrypy有两个值得关注的地方,一是URI与Callable对象的映射规则,一是Configuration文件的使用。

这里的Callable对象是一个"exposed = True"的函数或者有__call__方法的实例,以对象属性的形式构成树形结构。Get和Post的内容以命名参数的形式传入,特殊名称index匹配"/"而default则将URL的剩余部分作为调用的参数。
以下是一个简单的示例:
#+BEGIN_SRC python
import cherrypy
class Main(object):
    @cherrypy.expose
    def index(self):
        return "Hello World!"
    @cherrypy.expose
    def about(self):
        return "Page About<hr />"
class Page(object):
    @cherrypy.expose
    def index(self,q=None):
        return "Page <index>"+("<br />%s"%q if q else "")
    @cherrypy.expose
    def default(self,page_id):
        return "Page %s"%page_id
main = Main()
main.page=Page()
cherrypy.quickstart(main)
#+END_SRC

Cherrypy的配置文件使用了ini的格式(以dict形式写在Py代码中也是可以的),包括针对全局"global"的属性以及针对路径如"/"|"/static"等等的。配置可以作为调用cherrypy.quickstart时的参数,或者用cherrypy.config.update更新全局配置cherrypy.tree.mount为路径添加配置。
例如存在config.ini:
#+BEGIN_SRC ini
[global]
server.socket_port = 8000
server.thread_pool = 10
tools.sessions.on = True
tools.staticdir.dir = "/path/to/app"
[/static]
tools.staticdir.on = True
tools.staticdir.dir = "static"
#+END_SRC
然后是修改很小的HelloWorld程序:
#+BEGIN_SRC python
import cherrypy
class Main(object):
    @cherrypy.expose
    def index(self):
        return "Hello World!"
cherrypy.quickstart(Main(),"/","config.ini")
#+END_SRC

关于CherryPy基本的信息就是这样了。其他信息如自定义URL调度,Sessions机制,Request/Response对象,Tools模块,Plugins机制以及其他更多的Web开发中会用到内容在这里将不再详述。
现在的TurboGears1.1分支依然以CherryPy作为其Controller的部件,模板用的是Genshi,Model部分是SQLAlchemy,还有一个Py味道的MochiKit作为Javascript库。


* Tornado

Tornado是FriendFeed所使用的非阻塞Web服务器,具有优异的特性,可用于构建实时服务。
在接口提供上有对web.py和Django的参照,所以使用起来会有些许似曾相识的感觉。
其自带一份说明文档和若干示例代码,API的信息在其GIT仓库中查询。
首先依旧是HelloWorld,代码有Tornado首页提供:
#+BEGIN_SRC python
import tornado.httpserver
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
application = tornado.web.Application([
    (r"/", MainHandler),
])
if __name__ == "__main__":
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
#+END_SRC
从正则匹配后调用对应提供get或post方法的类,这正是Web.py的方式。
而模板引擎和Web.py一样是转化render为Py代码(而没有以解释的方式),不过标签是使用Django中{{}}和{%%}来嵌入。
Django的自定义标签这里叫UIModule,在通过RequestHandler或其子类派生的控制器(可有initialize方法用于初始化)中Tornado提供方法通过self调用,返回text/html/json或其他数据流,Post的内容由get_argument和self.request访问,用户状态设置cookie_secret后由Secure cookies存放,应用的配置通过Application构造器传入,有类似的CSRF的XSRF模块,可以提供静态文件,有和Django的Authentication功能相关的用户验证模块(有authenticated修饰器和login_url设置),翻译的文本由csv格式存放,部署的话多实例结合nginx服务器使用。
以上内容先暂且大略说这么些,因为以上内容并不是使用Tornado的有所特别的地方。

下面来说Tornado中特色的功能了——Asynchronous机制。
添加了"@tornado.web.asynchronous"的RequestHandler子类的get方法在结束时请求会依然保持打开,直到调用了self.finish而不是return的时候才会像客户端返回相应。
这样的作用是例如在读取远程文件(包括运程调用等待返回结果)这种需要一定时间的操作时,可以传入一个回调函数来进行之后需要的操作,而不必在自身过程中等待可以去继续执行之后的语句。
这和浏览器中JQuery包装的Ajax函数在原理和接口上有类似的地方。
在调用异步执行的方法(例如由AsyncHTTPClient提供的)时,回调函数在RequestHandler中可以以callback=self.async_callback(self.on_response)形式的参数(这里的async_callback不是必须的,是一个wrapper以添加调用参数)传入,这里的on_response是自行编写的用于处理异步方法返回结果的方法。

一样明显的使用的例子的聊天室程序:
其工作方式是存在一个以async方式的poll方法,创建async_callback对象添加到waiterList中,并在客户端push时去处理这个List中残留的项目。
客户端可以在发送消息时执行push操作,并让异步执行的回调函数之间构成一个循环。
可以的优化是客户端保存并发送一个cursor让服务端只返回需要的数据,还有在poll的时候如果有可以返回的数据就直接返回而不再往waiterList添加新的callback对象。
因为XSRF的使用,在客户端get或post时要传入用作验证的值。
Tornado自带的示例还考虑的不使用Ajax时伪静态的页面也能够正确的通过form和render来正确显示,示例中Ajax使用JQuery库。
这个试验代码写起来有点头晕,效果会比用setInterTime实现的感觉要好,而且最好还是去放到Linux下运行,先保证it just work。
测试用代码:
#+BEGIN_SRC python
见Tornado自带示例
#+END_SRC


* Twisted

一个事件驱动的Python网络框架,可以用来构建高效的Game和ZOPE服务器。
因为用法(去实现事件)是抽象后暴露出来的,和之前的Socket的时候有不同的关注层面。
可以把写Qt代码的感觉找出来一点的,就像去实现自己的Widget一样,虽然说没用抽象的信号机制而是只用到了override的方式事件循环。同时,和Tornado一样,是构建了一个异步非阻塞网络服务器。

最简单的使用是:
通过派生Protocol来实现事件代码,有self.transport用于传输数据,类似于Python库中SocketServer.StreamRequestHandler的作用。
Factory是用来制造的Protocol的子类,只需要一个。
reactor使用Factory的,进行事件循环,负责整个程序的执行,类似于Application对象的作用。
首先启用作为Web服务器。
然后来实现自己的一段简单的代码,不过先乱如一段WebServer代码,这和Cherrypy是同样的作用:
#+BEGIN_SRC python
from twisted.web import server, resource
from twisted.internet import reactor

class Root(resource.Resource):
    isLeaf = True
    def render_GET(self, request):
        return "Hello World"
resource = Root()
site = server.Site(resource)
reactor.listenTCP(8080, site)
reactor.run()
#+END_SRC
接下来是和SocketServer同样原理的一段代码:
#+BEGIN_SRC python
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
class QOTD(Protocol):
    def connectionMade(self):
        self.transport.write("Hello World")
        self.transport.loseConnection()
factory = Factory()
factory.protocol = QOTD
reactor.listenTCP(8000, factory)
reactor.run()
#+END_SRC
此外还有reactor.callLater添加回调,也可以把回调添加到Deferred对象中,实现Tornado中的那种异步调用。

由于Twisted具有较大的规模和复杂度,所以这里简短的介绍就暂且到这里不再往下了。


* 其他

org-mode中贴源码是用
#+BEGIN_SRC python
#+END_SRC
其实还需要`C-c C-e t'
#+OPTIONS:   H:3 num:t toc:t \n:t @:t ::t |:t ^:nil -:t f:t *:nil <:t
来让导出的显示符合预期

在Web开发中方便调试会对Py模块使用reload机制

貌似在Web开发中涉及模型后直接生成CURD的URL和View会是一个很好的原型。

State Machine是状态机的意思。

2010年9月21日星期二

摘 <- 暑

依然简单是书籍摘要性质的科普贴,算是起扩充话题之用。

* 《心理测验——原理与实践》
** 测验的要素
*** 编制
涉及测验的目标分析,测题的编写技术,测验的编排和组织。
*** 实施与计分
测试的环境以及主试与被试双方的态度、心理和准备会有测验的结果有一定的关联。
计分中涉及对猜测的校正。
*** 分数
原始分数可依照不同的统计方法导出集中参照分数。
参照常模解释分数:将被试的分数直接或间接的以在某个团体中的相对等级或相对位置来表示。
有时也以校标直接对被试者进行衡量。
** 测验的评价
*** 信度
用以表示测试结果的一致性和稳定性,而不是偶然性。
一个人测验的分数是其真实分数和非系统测量误差之和。
衡量的方法有:重测信度和复本信度,内部一致性信度,评分者信度,测量标准误差。
此外在样本团体的性质,测验的长度和难度都会对测验的信度产生影响。
*** 效度
用以表示测验能够测量到所要的测量对象的程度。
在数值上定义为与测量目标有关的真实分数方差与总分方差的比率。
效度和信度是用来衡量不同方面测验的误差的。
其类型可分为:内容效度,校标关联效度,构想效度。
测验的效度可被用于测验对被试者的预测以及分类作用。
*** 项目分析
是指根据被指者的反应对组成测验的各个题目/项目进行分析。
可包括:项目难度,项目鉴别度,以及其他要素的分析或模型的建立。
** 测验的类型
*** 智力测验
从题目类型和测试目的上可以划分出智力相关的若干因素:
1) 常识,领悟,算数,相似性,数字广度,词汇,数字符号,填图,积木图案,图片排列,物体拼凑。
2) 语文理解,数字,空间,知觉速度,词语流畅,记忆,归纳推理。或者,从思维的内容操作产物三个角度来说。
*** 成就测验
通常用于测试受试者对某项学科或某组学科经过学习和训练所获得的知识和技能。
*** 能力倾向测验
反应个体从未来训练中获益的能力,测量被试者的潜在成就或预测将来的作为水平,可用于学术和职业咨询。
可包括:感知觉和心理运动能力测验,机械能力测验,文书能力测验,艺术和音乐能力测验。
同时学术能力,工业能力,军事能力,以及创造力也可作为测验的方向。
*** 兴趣、态度和价值观的测量
*** 人格测验
反应人的气质
** 其他
测验按照被试对象可分为个人测验和团体测验。
====
其中也有关于应试训练和考试中的态度、动机、期望、需要什么的。




《判例的法理》
从功能上看,判例的作用是多方面的。
美国法官万斯庭认为,遵循先例原则的作用是:
(1)在同一管辖区域内,遵守先例使得法律管辖的人能够更准确地预见法律对他们的要求。
(2)遵守先例避免混乱,混乱是法官武断判案,采取完全不同态度对待每一个当事人和案件的结果。
(3)它可以避免不必要的工作,使法官能够更有效地处理一些常规和重复的案件。
(4)可使上级法院在一定程度上控制下级法院,以协调法官的工作。
(5)消除人们的不满。遵守先例支持了我们正当程序意识和法律平等保护意识,在全社会形成法治观念。
(6)在一个大的国家,尤其是当出现不同的宗教或偏离全国性规范的内部团体时,遵守先例提供了一个团结整个国民的统一力量。

尽管判例的概念没有出现在我国的制定法中,但可以预测将来的走向:
(1)在价值取向上,由指导审判转向总结经验。
(2)在形式主体上,由一元集权转向多元分权。
(3)在工作安排上,由宏观规划转向具体操作。

法律推理是指法官在法律适用过程中从查证的事实和确定的法律规范出发推论出判决或裁定的方法。
增强司法公信力,其具有重要的意义:
(1)限制法官判案之任性。
(2)便利上级法院的监督。
(3)促使法官的自我省思。
(4)预测法律的发展趋势。
判例法的推理机制是“将一项由先例提炼出的论断视同一项法则并将之适用于后一个类似的情境只是哦那个。
具体而言,这一过程分为三步,即首先要提炼出个案之间的相似之处,然后总结出先例中蕴含的相关法则,最后再将此相关法则运行于当下的个案之中。”
这揭示了判例法中推理形式三个先后相继的阶段
(0)推理前提:判例法是首要的法律渊源。(而未以成文法作为普通法的源泉)
(1)类比推理:将带解决案件与先例相连接。(包括相似与相异,以及其中的主要方面)
(2)归纳推理:从先例中抽象出法律原则。(特殊到普遍)
(3)演绎推理:将法律原则用于待决案件。(逻辑的三段论,寻找大前提,确定小前提,推出结论)

判例是法的价值的实现途径,体现在:
(1)维护社会秩序
(2)保证法律统一
(3)提高审判效率
(4)保障法律平等
(5)实现公平正义观念。
同时,判例是法制建设的促进手段,体现在:
(一)对立法的意义
(1)判例是法律具体化的重要途径
(2)判例是一种立法试验
(3)判例是一种造法机制
(4)
(二)对裁判的意义
(1)统一法院裁判尺度
(2)落实审判公开制度
(3)推动裁判文书改革
(4)提高审判工作效率
(5)升华法官审判经验
(三)对守法的意义
(1)预测裁判的可靠素材
(2)法制教育的生动素材
(四)对法学的意义
(1)法学研究的重要对象
(2)法学教育的有效方法
判例也体现出一定的政治功能:
(1)规范政治行为
(2)协调政治关系
(3)促进政治发展
(4)解决政治问题
在分析判例的短处中,可以做到扬长避短:
(1)保持僵化
(2)模糊含混
(3)律师恶用
(4)悖逆体制
(5)人才匮乏

关于判例的效力来源,有规范法学和现实主义法学两种具有代表性的研究方法。
出于对判例研究不同的目的和功能,
在前者的视野中,判例的约束力往往被转化为正式的法律渊源、法律形式、法律效率等问题。
在其总的理论框架之下,又包括了法律授权说、法律规范说、依附法律说和次要法院等几种具体的观点。
而后者的意图在于与描述法院或人民实际行动之范围,不信任传统的法律规则和概念。
另一种与实际有效说同属于社会学法学的关于判例约束力的观点叫做有效习惯说。
我国如果采用现实主义法学的方法对判例约束力问题进行分析,人们的认识将:
(1)由孤立考察转向全景关照
(2)由单向制约变为双向互动
(3)由效力有无转向效力强弱
在英美法系,判例可分为有约束力的判例与有说服力的判例。
在大陆法系,判例是非正式的法律渊源,不具有制定法那样的权威性,但有时判例依然有很强的实际约束力。

裁判摘要是对法院判决意见进行简要概括所抽象出的主要内容。
不同于大陆法系,在英美法系中,人们可以“不加批评地使用在发表的判决前面所载的‘判决要旨’。这类判决要职地法院的判决的根本性法律思想的内容提供了极为简洁抽象的说明,但它们却省略了基本的事实,或只予提示,而不提供判决所根据的理由”。

审判长简介的判例意义在于:
(1)法官个性是判例中的内在要素。
(2)凸显审判长在判例形成中的重要作用。
(3)激发法官造法的积极性。
(4)丰富判例的内容。

在司法过程中和其他相似的法律现象相比,司法过程中的法律拟制具有鲜明的特征:
(1)是解决法律问题的实践方法。
(2)是一种裁判方法。
(3)是把虚假视为真实、虚无当做实在的一种裁判方法。
(4)是法官用来实现公平正义的一种裁判方法。
综上所述,司法过程中的法律拟制,是法官为了实现公平正义的价值目标,而把无视为有、将有当做无的一种裁判方法。
其作用在于:
(1)法律进化的有效途径。
(2)价值实现的婉转方式。
(3)稳中求进的司法技艺。
其运作方式是:
(1)偏重于“本质的类似”。
(2)经由法律解释而进行。
(3)掩饰判决的真正理由
(4)改变案件事实的性质。
环境的制约,一方面是社会环境的改善,另一方面需要保障措施的设置:
(1)彰显基本人权价值。
(2)强化程序控制机制。
(3)完善判例制度。
(4)明确裁判的说理义务。
(5)实现立法预警机制。

司法建议,或者“附带意见”,是指法律意见中超出了处理问题的必要范围陈述。
附带意见中的主张对后来的案件没有约束力。其特征有:
(1)方法上被动与主动的统一。
(2)视野上个案与大局的统一。
(3)过程上案结与事了的统一。
(4)作用上的自愿与约束的统一。
附带意见尽管与当事人的诉争没有直接的关系,但也是判例的组成部分,有着不可忽视的说服力。

不同意见制的特征:
(1)法官独立做出判断。
(2)公开各种意见。
(3)调和各种意见的冲突。
(4)明确裁判的责任。
其积极作用在于:
(1)改善判例的构成。
(2)提高判例的质量。
(3)预测判例的走向。
(4)发展判例的契机。

法官与学者在判例问题之上携手合作,促使司法实践与法学研究的良性互动,推动着法律制度的不断发展:
(1)经由判例形成的法理论。
(2)学术论证促成判例定型。
(3)理论批判推动判例发展。
(4)法官与学者的合作的思考。

兰德尔案例教学法。

摘录完毕。




《逃避自由》
此书见到过两个版本,详略不同。
是说人面对发展而显示出的无力,以及由此而来的保护机制(联络,权利,SM或者逃避)。
自己前面有篇小说参考到了其中的观点。


这算一篇闲散书话吧。

2010年9月1日星期三

碎碎碎碎-杂物

散碎的东西

× Pastebin
http://pastebin.com/
一个网络上的粘贴板,通过短地址共享,设计用来传代码的。
支持语法加亮,并提供API,在一些IDE里有集成。

× codepad, an online compiler/interpreter
http://codepad.org/
在线编译/解释运行输入的代码并返回结果,支持众多语言,正好本机。
原理的话是沙箱+管道,写两个脚本便可以了。
另一给类似的实现是Lua官网上那个,有提供源码可下载。

× google-code-prettify
http://code.google.com/p/google-code-prettify/
代码显示加亮,js+css代码,GoogleCode上就在用。
是客户端渲染,加入到HTML网页感觉性能轻量,且自动支持众多代码。
功能类似的库也有若干,不过个人已经对这个比较喜欢了。

× CodeMirror: In-browser code editing
http://codemirror.net/
支持多种格式语法加亮的在线文本编辑控件。
已有一些网络应用中嵌入使用了,用来在线编写并执行代码。
记得貌似维基百科上对相似的东西会有一个专门的比较用词条。

× Granola
http://grano.la/
一个帮助电脑节电的软件,有特别的算法动态调整系统性能。
在Windows和Linux下都提供了对应的版本。

× ACGzz在线动漫播放器
http://www.acgzz.com/
提供一个小型的客户端,对优酷上的ACG资源有整理并持续跟新。
直接看资源列表的话可用:http://www.acgzz.com/player/?do=anime

× Opera Unite
很亮不过自己没用,服务器和客户端的结合。
展示本机的一个平台,默认提供文档分享等应用。
还是有人一直开的,通过别人的opera账户对应的地址访问。

× Kepler
http://www.keplerproject.org/
Lua的Web开发项目,包括服务器,CGI库,MVC框架,一个CMS应用,一系列工具及组件。
使用名为LuaRocks的组件安装工具,和Lua一样给人小巧的感觉结构简明。

× websh
http://tcl.apache.org/websh/
Tcl的Web应用开发组件,供Tcl语言使用。
和上面那个一样,供观摩的话会有些启发,貌似日常不会用到。

× php.js
http://phpjs.org/
PHP自带函数的Javascript实现,需要时使用即可。
例如一些成对的PHP函数,或者将一些代码移到客户端上。
免去自己再去实现一个php里有但js里没有的函数了。

× surrogafier
http://bcable.net/project.php?surrogafier
一个PHP写的在线代理(Web Proxy)应用,实现得算不错,可以用。

× SLIB
http://people.csail.mit.edu/jaffer/SLIB
a portable library for the programming language Scheme.
在众多Scheme实现下可以使用,包括Kawa,MzScheme貌似也可以。

× Readability
http://lab.arc90.com/experiments/readability/
一段放入书签中使用的代码,能够只显示当前网页的正文文本。

× PageZipper
www.printwhatyoulike.com/pagezipper
一段放入书签中使用的代码,能够自动展开多页的网页在一页内显示。

× Firebug Lite
http://getfirebug.com/firebuglite
一段放入书签中使用的代码,能够在当前网页上使用Firebug进行调试。

× 搜狗云输入法,QQWeb输入法
一段放入书签中使用的代码,能够在当前网页上使用中文输入法。
在线的输入法以前有过,虽然速度较快,但没能嵌入网页并使用远程词库。

× GoogleChrome的插件
以前把自动升级关了,所以直到现在才发现插件是很好用的东西。
感觉插件管理比Firefox省心,查找和设置操作进行的很流畅。

× Ultimate++
http://www.ultimatepp.org/
类似Qt的C++跨平台开发框架,包括IDE模块也很完整了,编译时间有点痛苦。
设计亮点是对跨平台的封装,以及精巧的API设计,有DSL化的代码风格。

× JDMCox Software
http://jdmcox.com/
某人退休后的Windows小程序,普遍exe文件很小依赖也少,并提供C代码。
有个PianoRollComposer是个MIDI编辑器,功能不少,就是界面有点抽象。

× TiddlyWiki - a reusable non-linear personal web notebook
http://www.tiddlywiki.com/
单HTML的本地CMS,作为个人的GTD应用。
直接在浏览器中交互使用,有插件机制,也可Web应用共享。

× 16K MUD competition
http://www.andreasen.org/16k.shtml
MUD是古老的文字型终端网络游戏,国内以LPC脚本的MudOS为常见。
这是很多简单却完整的MUD游戏实现,有C也有Python写成的。

× SharkyPy
http://www.heim-d.uni-sb.de/~heikowu/SharkyPy/
an implementation of a Kademlia Distributed Hash Table.
Kad是eMule中的P2P共享网络,分布式无需集中的服务器。

× ejacs - JavaScript/EcmaScript interpreter for Emacs
http://code.google.com/p/ejacs/
Emacs中的类Narcissus的JavaScript Engine实现,是一个动态语言的解释器。

× WikiTaxi
http://www.wikitaxi.org/
一个离线的Wikipedia浏览工具,可去下载维基百科的备份包来导入。

× Squirrel - The Programming Language
http://www.squirrel-lang.org/
一个类Lua的脚本语言,语法更像Java。

× Resynthesizer
http://www.logarithmic.net/pfh/resynthesizer
a Gimp plug-in for texture synthesis.
可以用来去除,纹理,放大图像上的物体。

× ZGameEditor Main/The tool for creating 64kb games!
http://www.zgameeditor.org/
一个小巧的3DGAME可视化创作套件,有Object和Script供使用。

× Luaj
http://sourceforge.net/projects/luaj/
J2ME和J2SE中实现的Lua环境。

× wxBasic
http://wxbasic.sourceforge.net/
Basic解释器+WxWidget绑定,有实现方面的文档。

× Free Qt Applications - Qt-Apps.org
http://qt-apps.org/
Qt开源项目的集中地。

× Kohana
http://kohanaframework.org/
CodeIgniter的社区分支,更加OOP,包含ORM组件。
如果熟悉ORM的话,CI的模型类显得单薄了一些。

× Qemu Manager
http://www.davereyn.co.uk/
一个便携的Qemu的Windows下图形前端,小巧便携是其特点。

× NetFront browser
移动平台的完整浏览体验,和OperaMobile或WebkitMobile是类似的东西。
可见于日式产品中,性能优异。

× wwwsqldesigner - Visual web-based SQL modelling tool
http://code.google.com/p/wwwsqldesigner/
网页中的可视化数据库建模工具

× Yokadi
http://yokadi.github.com/
a command line oriented, sqlite powered, todo list system.
关键词是CLI,GTD,PIM。

× 5 Days A Stranger
http://www.fullyramblomatic.com/5days/
一个免费的冒险类游戏

× strip
GCC组件之一,用于去除可执行文件的符号信息。
等于-s参数,用于减少文件体积,对库文件勿用。

× Harmony
http://rabotik.nl/harmony.htm
一个精彩的DOOM游戏,运用了一系列免费工具。

× Panda3D - Free 3D Game Engine
http://www.panda3d.org/
迪斯尼在用,核心是C++,默认是可选的Python接口。

× PythonCard
http://pythoncard.sourceforge.net/
wxPython的类HyperCard实现,用于构建GUI程序,也像VB。

× xajax PHP Class Library
http://xajaxproject.org/
服务端的JavaScript代码生成库,用于AJAX,Django也有类似第三方实现。

× EasyWebServer网站服务器
http://www.onlinedown.net/soft/47720.htm
一个小巧的Windows下Web服务器实现,有CGI和ISAPI支持。
Python中也自带了类似的功能,不过这个非常小巧和完整。

× Delphi For PHP
可视化的web应用程序开发工具,运用VCL和AJAX技术。
国内有个叫网站·搭建者的实现的类似的拖拽式东西。

× JyRCP - Create GUIs in Jython based on the Eclipse RCP platform
http://code.google.com/p/jyrcp/
= Jython + Rich Client Platform

× Camelot
http://www.python-camelot.com/
an open source RAD framework that leverages Python, Sqlalchemy and Qt to build rich desktop applications.
实现了数据库数据访问的GUI。

× Notus
http://notus.sourceforge.net/
一个非MFC的GUI框架,运用模板减少继承结构。


暂且随意的堆放一下,能用则可用之,或者纯观摩用。

2010年8月25日星期三

两份文本

原文授权都是public domain

Bible (King James)/Genesis
Chapter 1

1 In the beginning God created the heaven and the earth.
2 And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters.
3 And God said, Let there be light: and there was light.
4 And God saw the light, that it was good: and God divided the light from the darkness.
5 And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day.
6 And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters.
7 And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so.
8 And God called the firmament Heaven. And the evening and the morning were the second day.
9 And God said, Let the waters under the heaven be gathered together unto one place, and let the dry land appear: and it was so.
10 And God called the dry land Earth; and the gathering together of the waters called he Seas: and God saw that it was good.
11 And God said, Let the earth bring forth grass, the herb yielding seed, and the fruit tree yielding fruit after his kind, whose seed is in itself, upon the earth: and it was so.
12 And the earth brought forth grass, and herb yielding seed after his kind, and the tree yielding fruit, whose seed was in itself, after his kind: and God saw that it was good.
13 And the evening and the morning were the third day.
14 And God said, Let there be lights in the firmament of the heaven to divide the day from the night; and let them be for signs, and for seasons, and for days, and years:
15 And let them be for lights in the firmament of the heaven to give light upon the earth: and it was so.
16 And God made two great lights; the greater light to rule the day, and the lesser light to rule the night: he made the stars also.
17 And God set them in the firmament of the heaven to give light upon the earth,
18 And to rule over the day and over the night, and to divide the light from the darkness: and God saw that it was good.
19 And the evening and the morning were the fourth day.
20 And God said, Let the waters bring forth abundantly the moving creature that hath life, and fowl that may fly above the earth in the open firmament of heaven.
21 And God created great whales, and every living creature that moveth, which the waters brought forth abundantly, after their kind, and every winged fowl after his kind: and God saw that it was good.
22 And God blessed them, saying, Be fruitful, and multiply, and fill the waters in the seas, and let fowl multiply in the earth.
23 And the evening and the morning were the fifth day.
24 And God said, Let the earth bring forth the living creature after his kind, cattle, and creeping thing, and beast of the earth after his kind: and it was so.
25 And God made the beast of the earth after his kind, and cattle after their kind, and every thing that creepeth upon the earth after his kind: and God saw that it was good.
26 And God said, Let us make man in our image, after our likeness: and let them have dominion over the fish of the sea, and over the fowl of the air, and over the cattle, and over all the earth, and over every creeping thing that creepeth upon the earth.
27 So God created man in his own image, in the image of God created he him; male and female created he them.
28 And God blessed them, and God said unto them, Be fruitful, and multiply, and replenish the earth, and subdue it: and have dominion over the fish of the sea, and over the fowl of the air, and over every living thing that moveth upon the earth.
29 And God said, Behold, I have given you every herb bearing seed, which is upon the face of all the earth, and every tree, in the which is the fruit of a tree yielding seed; to you it shall be for meat.
30 And to every beast of the earth, and to every fowl of the air, and to every thing that creepeth upon the earth, wherein there is life, I have given every green herb for meat: and it was so.
31 And God saw every thing that he had made, and, behold, it was very good. And the evening and the morning were the sixth day.


United States Declaration of Independence
In CONGRESS, July 4, 1776.
A DECLARATION
By the REPRESENTATIVES of the
UNITED STATES OF AMERICA,
In GENERAL CONGRESS assembled.
WHEN in the course of human Events, it becomes necessary for one People to dissolve the Political Bands which have connected them with another, and to assume among the Powers of the Earth, the separate and equal Station to which the Laws of Nature and of Nature’s God entitle them, a decent Respect to the Opinions of Mankind requires that they should declare the causes which impel them to the Separation.
We hold these Truths to be self-evident, that all Men are created equal, that they are endowed by their Creator with certain unalienable Rights, that among these are Life, Liberty, and the pursuit of Happiness—-That to secure these Rights, Governments are instituted among Men, deriving their just Powers from the Consent of the Governed, that whenever any Form of Government becomes destructive of these Ends, it is the Right of the People to alter or abolish it, and to institute a new Government, laying its Foundation on such Principles, and organizing its Powers in such Form, as to them shall seem most likely to effect their Safety and Happiness. Prudence, indeed, will dictate that Governments long established should not be changed for light and transient Causes; and accordingly all Experience hath shewn, that Mankind are more disposed to suffer, while Evils are sufferable, than to right themselves by abolishing the Forms to which they are accustomed. But when a long Train of Abuses and Usurpations, pursuing invariably the same Object, evinces a Design to reduce them under absolute Despotism, it is their Right, it is their Duty, to throw off such Government, and to provide new Guards for their future Security. Such has been the patient Sufferance of these Colonies; and such is now the Necessity which constrains them to alter their former Systems of Government. The History of the Present King of Great-Britain is a History of repeated Injuries and Usurpations, all having in direct Object the Establishment of an absolute Tyranny over these States. To prove this, let Facts be submitted to a candid World.
He has refused his Assent to Laws, the most wholesome and necessary for the public Good.
He has forbidden his Governors to pass Laws of immediate and pressing Importance, unless suspended in their Operation till his Assent should be obtained; and when so suspended, he has utterly neglected to attend to them.
He has refused to pass other Laws for the Accommodation of large Districts of People; unless those People would relinquish the Right of Representation in the Legislature, a Right inestimable to them, and formidable to Tyrants only.
He has called together Legislative Bodies at Places unusual, uncomfortable, and distant from the Depository of their public Records, for the sole Purpose of fatiguing them into Compliance with his Measures.
He has dissolved Representative Houses repeatedly, for opposing with manly Firmness his Invasions on the Rights of the People.
He has refused for a long Time, after such Dissolutions, to cause others to be elected; whereby the Legislative Powers, incapable of Annihilation, have returned to the People at large for their exercise; the State remaining in the mean time exposed to all the Dangers of Invasion from without, and Convulsions within.
He has endeavoured to prevent the Population of these States; for that Purpose obstructing the Laws for Naturalization of Foreigners; refusing to pass others to encourage their Migrations hither, and raising the Conditions of new Appropriations of Lands.
He has obstructed the Administration of Justice, by refusing his Assent to Laws for establishing Judiciary Powers.
He has made Judges dependent on his Will alone, for the Tenure of their Offices, and Amount and Payment of their Salaries.
He has erected a Multitude of new Offices, and sent hither Swarms of Officers to harass our People, and eat out their Substance.
He has kept among us, in Times of Peace, Standing Armies, without the consent of our Legislature.
He has affected to render the Military independent of and superior to the Civil Power.
He has combined with others to subject us to a Jurisdiction foreign to our Constitution, and unacknowledged by our Laws; giving his Assent to their Acts of pretended Legislation:
For quartering large Bodies of Armed Troops among us:
For protecting them, by a mock Trial, from Punishment for any Murders which they should commit on the Inhabitants of these States:
For cutting off our Trade with all Parts of the World:
For imposing taxes on us without our Consent:
For depriving us, in many Cases, of the Benefits of Trial by Jury:
For transporting us beyond Seas to be tried for pretended Offences:
For abolishing the free System of English Laws in a neighbouring Province, establishing therein an arbitrary Government, and enlarging its Boundaries, so as to render it at once an Example and fit Instrument for introducing the same absolute Rule in these Colonies:
For taking away our Charters, abolishing our most valuable Laws, and altering fundamentally the Forms of our Governments:
For suspending our own Legislatures, and declaring themselves invested with Powers to legislate for us in all Cases whatsoever.
He has abdicated Government here, by declaring us out of his Protection and waging War against us.
He has plundered our Seas, ravaged our Coasts, burnt our Towns, and destroyed the Lives of our People.
He is, at this Time, transporting large Armies of foreign Mercenaries to compleat the Works of Death, Desolation, and Tyranny, already begun with circumstances of Cruelty and Perfidy, scarcely paralleled in the most barbarous Ages, and totally unworthy the Head of a civilized Nation.
He has constrained our fellow Citizens taken Captive on the high Seas to bear Arms against their Country, to become the Executioners of their Friends and Brethren, or to fall themselves by their Hands.
He has excited domestic Insurrections among us, and has endeavoured to bring on the Inhabitants of our Frontiers, the merciless Indian Savages, whose known Rule of Warfare, is an undistinguished Destruction, of all Ages, Sexes and Conditions.
In every stage of these Oppressions we have Petitioned for Redress in the most humble Terms: Our repeated Petitions have been answered only by repeated Injury. A Prince, whose Character is thus marked by every act which may define a Tyrant, is unfit to be the Ruler of a free People.
Nor have we been wanting in Attentions to our British Brethren. We have warned them from Time to Time of Attempts by their Legislature to extend an unwarrantable Jurisdiction over us. We have reminded them of the Circumstances of our Emigration and Settlement here. We have appealed to their native Justice and Magnanimity, and we have conjured them by the Ties of our common Kindred to disavow these Usurpations, which, would inevitably interrupt our Connections and Correspondence. They too have been deaf to the Voice of Justice and of Consanguinity. We must, therefore, acquiesce in the Necessity, which denounces our Separation, and hold them, as we hold the rest of Mankind, Enemies in War, in Peace, Friends.
We, therefore, the Representatives of the UNITED STATES OF AMERICA, in General Congress, Assembled, appealing to the Supreme Judge of the World for the Rectitude of our Intentions, do, in the Name, and by the Authority of the good People of these Colonies, solemnly Publish and Declare, That these United Colonies are, and of Right ought to be, Free and Independent States; that they are absolved from all Allegiance to the British Crown, and that all political Connection between them and the State of Great-Britain, is and ought to be totally dissolved; and that as Free and Independent States, they have full Power to levy War, conclude Peace, contract Alliances, establish Commerce, and to do all other Acts and Things which Independent States may of right do. And for the support of this Declaration, with a firm Reliance on the Protection of the divine Providence, we mutually pledge to each other our Lives, our Fortunes, and our sacred Honor.
Signed by Order and in Behalf of the Congress,
JOHN HANCOCK, President.
Attest.
CHARLES THOMSON, Secretary.
Philadephia: Printed by John Dunlap.


读起来都很有感觉的样子,比如说是从逻辑上坚信着什么的并将之表达出来,而成为构成人身体之外的若干要素,并使得以判断力去支持人去做出些什么。

2010年8月22日星期日

ORM & Serialization in Python

这篇依旧是导读性质的一篇,在看Python自带文档缺少头绪的时候可以参考,不然就是在被误导了哦。
而且其实呢,闲扯才是这篇的真正目的呢,虽然说貌似没什么想说的,唉还是在胡言乱语来着的。

之所以要****,是为了存储或传输。

Qt中使用的方式是通过流来实现的,提供x,x方法,并通过重载<<以及>>运算符来实现接口。

虽然标题什么的是已经确定了话题的方向,不过下面的内容只是在随意地跑跑而已。


* import

直接导入py文件或pyc文件,适合存放开发中的自定义数据。


* pickle

用于Python对象和数据流见的转化,用于数据持久化
最简单的示例是:
pickle.dump(data, open('save.p', 'wb'))
reader = pickle.load(open('save.p', 'rb'))
data是需要保存的类型,通常是个字典
可以往一个file对象dump/load多次
pickle的dumps和loads则是用字符串代替文件
对于自己定义类型的实例,可以提供__getstate__/__dict__以及__setstate__
其保存的数据格式会有不同版本,不过文件是保持向后兼容的
似乎pickle是Py的类似模块中最通用的选择,即处于比较暴露的接口
关联的模块marshal和shelve有不同的用法。

试验代码:
#+BEGIN_SRC python
import pickle
class MyObj1:
     def __init__(self,value):
        self.value=value
class MyObj2:
     def __init__(self,value):
        self.value=value
     def __getstate__(self):
        return self.__dict__.copy()
     def __setstate__(self,dict):
        self.__dict__.update(dict)
m1 = MyObj(6)
m2 = MyObj2(7)
data1 = {'str':"string",0:"zero",1:m1,2:m2}
save = pickle.dumps(data1)
data2 = pickle.loads(save)
print data1[2].value == data2[2].value
#+END_SRC


* json

Python中实现json编解码的模块提供了类似pickle的接口,提供load和dump方法。
具体的编解码操作由JSONEncoder/JSONDecoder提供,可以通过派生以cls参数使用或者添加hook的方式来添加对非内置对象实例的操作方法。

试验代码:
#+BEGIN_SRC python
import json
data1 = {0:1,1:2,2:3}
print json.dumps(data1,sort_keys=True)
def myhook(dct):
     return {"vector":"|".join(map(str,dct["vector"]))}
data2 = json.loads("""
{"vector":[1,2]}
""",object_hook=myhook)
print data2

class MyEncoder(json.JSONEncoder):
     def default(self, obj):
        if isinstance(obj, complex):
         return [obj.real, obj.imag]
        return json.JSONEncoder.default(self, obj)
print MyEncoder().encode(1+4j)
#+END_SRC


* XML

Python中和XML相关的实现且在文档中提供实例的有几个:
HTMLParser通过实现handle方法
xmlrpclib/SimpleXMLRPCServer这个用起来和XML感觉不大
xml.dom.minidom实现了简单的DOM接口
或者用SAX的接口的实现更好的解析性能
关于DOM与SAX的规范的内容并不在Py的范畴内
xml.parsers.expat亦有足够悠久的历史
xml.etree.ElementTree则是Py2.5中新增的
各自用法还算有明显的区别的,算是明显吧


* sqlite3

用sqlite3.connect创建Connection对象,可以文件可以":memory:",提供cursor方法获得Cursor对象,然后就找到我们的execute方法了。
可用“?”占位传入值,执行“select”后可对Cursor对象迭代,或者用Cursor对象的若干fetch方法来获取Row的数据。
事务方面的操作在Connection对象上。
可自定义converter来实现sqlite数据和Python对象的转化。

试验代码:
#+BEGIN_SRC python
import sqlite3
conn = sqlite3.connect(":memory:")
c = conn.cursor()
c.execute("create table name(key,value)")
c.execute('insert into name values (?,?)',("hello","world"))
conn.commit()
c.execute('select * from name order by key')
for row in c:
     print row
c.close()
#+END_SRC


* ConfigParser

用来读写ini格式的文件。
虽然是源于Windows的格式,Linux下还是有程序在用的。


* csv

用于读写CSV格式的文件,通过对文件建立reader和writer对象。


* codecs

用于读写UTF-8编码的文件,提供了open的同名函数


* StringIO

实现内存中的文件对象,接口按照对文件的方式使用,提供getvalue方法获取值。


* ZODB

Zope Object Database,就是Zope对象数据库的意思,不过可以作为独立的模块使用。
和Django开发中支持的MongoDB类似的,都属于NoSql的对象数据库,不过ZODB对Py有Native的感觉。
安装“easy_install ZODB3”,导入“import ZODB”,然后便可使用。
使用的接口类似于shelve模块(都默认仅在__setitem__之类的操作时探测到更新),
也就是说是依然dict对象提供的接口的方式使用一个root对象。
因为这里不去涉及ZOPE,所以也仅写一段just work的代码来试一试。

试验代码:
#+BEGIN_SRC python
from ZODB.FileStorage import FileStorage
from ZODB.DB import DB
from persistent import Persistent
class One(Persistent):
     def __init__(self):
        self.todo=[]
     def add(self,task):
        self.todo.append(task)
        self._p_changed = 1
storage = FileStorage('Data.fs')
db = DB(storage)
connection = db.open()
root = connection.root()
root['main']=["hello","world"]
import transaction
transaction.commit()
print root.items()
connection.close()
db.close()
#+END_SRC


* Django-norel

是一个让Django在NoSql数据库上模拟出Django原本的数据Model的查询的Django分支,在Google App Engine上写应用时在用。



* SQLAlchemy

对象关系映射,也就是通常缩写为ORM(Object-relational mapping)的东西。
使用了ORM可以通过OO的方式方便使用数据库,并可方便的切换所使用的数据库后端。
SQLAlchemy虽然才在2006年发布了他的第一个版本,但是很快成为Python社区使用最广泛的ORM模块。
和Django的ORM模块作用是一样的,只不过Django的Model类一般只在Django应用里使用,而且不及SQLAlchemy复杂(至少不是只倾向暴露给用户一个最高层的接口)。
TurboGears的话,是目前尝试使用SQLAlchemy很好的实例,以及应用的价值所在。
如果利用好缓存的话,ORM的性能表现并没有对应用太大的影响。

安装“easy_install SQLAlchemy”,导入“import sqlalchemy”,
然后“sqlalchemy.__version__ ”便可以查看版本。

先来整理一下概念上的东西,并假定已有了简单的SQL和ORM的基础:
对象Engine,表示一个数据库,用create_engine创建。
对象MetaData表示对数据的操作,提供方法create_all/drop_all在Engine上创建或删除表
对象Table用以表示数据表,构造器可用于构造表,可在表实例上构建查询并以execute方法执行查询
对象Column表示数据表的列,列的类型定义在sqlalchemy.types。
declarative_base的实例Base是以申明的方式来创建对象,相比用mapper关联表和对象要直观,两者等价所以通常就以派生Base的方式使用了。有属性__table__表示关联的Table对象和属性metadata表示拥有的MetaData对象。
类型Session表示对数据库操作的会话,通过sessionmaker(bind=engine)创建,然后用来创建session实例。实例session有方法add/add_all和delete用于添加删除实例,方法query用以创建Query对象,方法commit和方法rollback用于事务的提交与回滚,方法from_statement直接执行SQL语句。
对象Query用于构建查询,在session实例上以所查询对象为参数创建,提供方法filter,order_by以及序列操作进行查询,提供方法all,one,firs以及count获得查询结果,方法join可以实现表的join查询,简单的查询操作便都在此进行。
aliased用于解决多表查询时的命名冲突问题。
外键列ForeignKey用来指向另一个表的主键,用以建立表间关系。数据实例的API通过relationship函数给模型添加属性。

当前手头没有打算写实际的例子,所以依然是试验目的的代码,目的仅是演示一下代码的流程:
#+BEGIN_SRC python
print "create_engine"
from sqlalchemy import create_engine
engine = create_engine('sqlite:///:memory:', echo=True)

print "declare_schema"
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
Base = declarative_base()
class Entry(Base):
     __tablename__ = 'entry'
     id = Column(Integer, primary_key=True)
     name = Column(String(50))
     category_id = Column(Integer, ForeignKey('category.id'))
     category = relationship("Category", backref="entries")
     def __init__(self,name,category):
        self.name = name
        self.category = category
     def __repr__(self):
        return "<Entry %s>"%self.id
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, backref
class Category(Base):
     __tablename__ = 'category'
     id = Column(Integer, primary_key=True)
     name = Column(String)
     #entry_id = Column(Integer, ForeignKey('entry.id'))
     def __init__(self,name):
         self.name = name
     def __repr__(self):
         return "<Category %s>"%self.id
Base.metadata.create_all(engine)

print "use_db"
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
c = Category("hello_world")
session.add(c)
session.add(Category("hello_earth"))
session.commit()
for i in range(1,10):
     item = Entry(str(i),c)
     session.add(item)
session.commit()
for i in session.query(Entry).filter(Entry.id==5).all():
     print i
     print i.category
print session.query(Category).count()

print "END"
#+END_SRC


* Elixir

Elixir构建在SQLAlchemy之上,提供直观易用的声明式接口。
在使用方式上Elixir类似于SQLAlchemy的declarative扩展,而且在API上有所简化以方便使用,也隐藏了一些映射的实现细节。

安装“easy_install Elixir”,导入“from elixir import *”,之后便可使用。
值得注意的是对于Elixir未包装的功能,SQLAlchemy的模块依然是需要且肯定会使用到的,特别是查询方面的Query对象。

然后直接写一段试验用的代码了:
#+BEGIN_SRC python
from elixir import *

metadata.bind = "sqlite:///:memory:"
metadata.bind.echo = True

class Post(Entity):
     using_options(tablename='post')
     title = Field(Unicode(30))
     content = Field(UnicodeText)
     comments = OneToMany('Comment',order_by='-id')
     def __repr__(self):
        return "<Post %s>"%self.title
class Comment(Entity):
     content = Field(UnicodeText)
     post = ManyToOne('Post')
     def __repr__(self):
        return "<Comment %s>"%(self.content[:5])

#from model import *
setup_all()
create_all()

p = Post(title=u"demo",content=u"This is a test post.")
for i in range(1,10):
     p.comments.append(Comment(content=u"#%s comment"%i))
session.commit()

for i in Post.query.all():
     print i,i.comments
p.delete()
print Post.query.count()

cleanup_all(True)
#+END_SRC


* Camelot

一个基于PyQt和Elixir依照Django的Model和Admin接口用于开发类似access桌面MIS的RAD框架。
内含一个类似[[http://code.google.com/p/formlayout/]]的form窗口生成工具。

这个就纯观赏用。


* Python

语言的解析树本身就是一个静态的数据,不过不会去直接使用它:
#+BEGIN_SRC python
import parser
st = parser.expr('a + 5')
print parser.st2tuple(st)
a = 5
code = st.compile()#same as 'parser.compilest(st)'
import pprint
pprint.pprint(eval(code))
#+END_SRC
较通常的做法呢是实现对象的__getattribute__/__getattr__方法,以及hasattr/getattr这样的方法,或者类似__class__/__dict__获得中对象所关心的属性。
不过通常也只是这样来获取数据,而没有把数据写成py文件的习惯(不然就等同于使用了罪恶的eval函数了)。


* 闲扯

因为目的是对想法的提及,所以依然还是想在行文逻辑上有连续的感觉。
(上面这句就有问题来着...)
在Django中,模板中数据的来源有两个方面,一是由视图传入的字典提供哦,一是在模板渲染时调用所编写的标签或过滤器返回的结果。对于单页面的网页在浏览器中缓存的是最终显示的结构,在访问新的数据时,仅在样式和脚本上有所缓存。
如果需要把未渲染的模板提前保存在本地的话,就需要在渲染时执行对服务器的全程调用,这就是当前Ajax技术所实现的事情。服务器返回的不再是完整的页面,而是html/text片段,或xml/json数据,或js可执行代码。
将本地的页面更多的作为显示的容器,还是将远程的调用仅涉及数据相关的API,是把功能实现在客户端还是服务器的两种倾向。
对于PyQt这样Api较封闭且脚本类的东西来说,利用漂亮的QWidget及其派生类树形结构。可以在本地程序中下载全程的代码,然后无缝地作为本地程序来执行。
Firefox的xul技术就是这样一种程序环境,程序以扩展的性质安装到本地,通过Market来分发,通过签名来保障安全。而且界面和Qt一样是本地的,而不仅作为嵌入而渲染。如今Eclipse,Notepad++都有各自的扩展Market,而IM之类的软件也可做这样的平台。
现在觉得Chrome的Market更好用一点,应为扩展更接近单纯的网页。虽然功能有些限制,不过填删与开发似乎觉得更方便一些。
不过FX的扩展有沙箱like的权限机制,相比在PyQt中去执行远端的代码就是一件危险的事情了(QML的事属于下面一行)。
说到浏览器,HTML5可用来构建富客户端了(代码执行环境放在本机,而数据的储存放在服务器上,代码可以根据需要动态的下载),和即使Debian的软件包可以做到高速的分发以及虚拟机一样快速且底副作用的部署的话,依然是可以感受的其中的区别的。
不过,区别只是出于观察的视角,在给予用户的体验上,之间又有相关联的地方。


闲扯居然也能坑这么久...也没质量什么的...


Sep 27 2010