|
|
29 Oktober 今天临晨零点四十六分,小米满一周岁了. 小米已经有七颗牙齿,第八颗也马上就要出来了. 小米已经可以自己走路了,虽然还有点摇摇晃晃的走不了多远. 小米已经能听懂很多话了,让他取"会叫的汽车"或者"眼睛会转的汽车"他已经能准确的找到了. 小米最喜欢的玩具就是汽车了,虽然他还不能准确的发"车"这个音而用"HE"来代替. 小米很喜欢听有节奏的音乐,并且会随着节奏点点头,因为经常用手机听"袋鼠妈妈",以至于现在他经常拿起我的手机就有节奏的点头.
昨天小米在楼下玩儿的时候,还给大家表演了小魔术呢. 小米把自己的奶瓶盖拿在手里玩一会,然后藏在自己屁股后面,然后伸出两手对大家说"没...没..." 连着玩了好几次,把大家都逗乐了.... :)
17 September 这几天小米经常会念叨"袋袋...袋袋...",我很纳闷,我只教他叫"爸爸",又没教他叫"爹爹",怎么老发这个音啊. 昨晚没事开着电视逗小米玩儿,小米突然听到了什么,一边随着音乐点头,一边手指着电视,嘴里又开始"袋袋...袋袋...",原来是某奶粉广告,呵呵.不过真的挺好听的"袋鼠妈妈有个袋袋,就是为了保护乖乖". 原来小米这几天念叨的,是这个广告歌啊.呵呵. 今天就把这歌拿来做手机铃声.
19 August 昨天下班回家,小米看见我还是一如既往的兴奋,我洗洗手就把他抱着走来走去.小家伙又同往常一样,兴奋了就用手使劲的拍我的脸.我故意板起脸训他几句,说:"不许这么打招呼,不许拍别人的脸..." 小家伙应该是看我脸色语气不好,竟然咧着嘴作势要哭.赶紧让小米妈妈哄了哄.还好小米不记仇,过一会我再去抱他玩儿,他依然很高兴就来了. 晚上他又拍妈妈的脸,妈妈也说他"不许这么打招呼",结果小家伙又咧着嘴要哭. 毕竟快十个月了.开始懂事了,知道大人是在训他了.呵呵.
又,小米今天学会用两手作揖表示"谢谢"了.
29 Juli 三十了. //sign
感觉一事无成.
岳飞在这个年龄都官拜节度使了.
今天发生了不少事情.
股市创了天量大幅下跌了.
卓琳同志逝世了.
焦柳铁路火车出轨了.
23 Juni 1. 6月9号中午12点左右,小米突然能自己往前爬了,其实准确来说还不能叫做爬. 但毕竟是他第一次能自主的向一个目标运动了.
2. 6月10号, 小米和妈妈回到了姥姥家了, 几天之后,发现小米的牙齿也露头了.
20 März 这次发现原来体检是强制的,又交了5元.
小米体重已经有8.6kg了,身长67cm
去得时候忘了带玩具了,在加上他有点犯困,多哭了几声.
过几天上照片. 12 Februar 今天早上去三环医院打防疫针,白百破第一针和糖丸第二次.
小米还是一如既往的坚强,打针只哭了两声,小米妈妈抱着他摇了摇,他就冲我笑了,真是个乖孩子.
打完针顺便做了下体检,感觉很不好,体检的地方是和普通门诊混在一起的,给小米体检的大夫同时也给别的大人和孩子看病,我有点担心这样会交叉感染的,婴儿体检应该有专门的地方才是,决定以后去三环医院只是去打针,不再做体检了.
小米的囟门有点小,不知道是不是长的太快了. 04 Februar 今天是小米来到这个世界上的第100天,到明天凌晨,小米就是百天宝宝了 :)
小米带给我的喜悦是无法用喜悦来形容的,就这样多了一个和我自己联系如此紧密的生命,每天看着他醒来,哭闹,玩耍,觉得生活无限美好.
小米已经大约有64cm高了,体重也有15斤了,这一百天小家伙长的真快.
02 Februar 初三小米在飞机起飞前拉了一次大大的臭臭,晚上又拉了一点点.然后后面几天就拉的比较少了.
初六中午小米的臭臭突然和以前不太一样了,以前经常是放射状并且比较稀,这次的臭臭变稠了,也没有四处喷开,拉了厚厚圆圆的一团.
初七一天没有拉,小米妈妈和我有些担心.
今天早上我刚出门,小米妈妈给我电话说小米又拉臭臭了,和初六拉的一样,只是量更多一些.
基本上可以确认小米开始攒肚了,小人儿肠胃发育到一个新阶段了. 09 Dezember 11月28日(农历十一月初一),小米满月了.
是记 05 Januar 该bug会导致模板类的静态成员被析构两次.样例代码如下:
//------------------------------------------------- // tmpl.h struct IFoo;
struct FooInst { ~FooInst(); IFoo* Get() { return _p_foo; } private: IFoo *_p_foo; };
struct IFoo { virtual ~IFoo(); };
template<class T> class Foo: public IFoo { public: static T* Inst() { return (T*)_inst.Get(); } virtual ~Foo() {} protected: Foo() {} private: static FooInst _inst; };
// bug. template<class T> FooInst Foo<T>::_inst;
class FooBar: public Foo<FooBar> { public: FooBar() {} };
int func();
//------------------------------------------------- // tmpl.cpp #include "tmpl.h"
// solution //template<> FooInst<FooBar>::_inst;
FooInst::~FooInst() { delete _p_foo; } IFoo::~IFoo() {} int func() { return (int)FooBar::Inst(); }
//------------------------------------------------- //main.cpp #include "tmpl.h"
int main(int, char*[]) { return func() + (int)FooBar::Inst(); }
//------------------------------------------------- # makefile # usage: nmake all CPP=$(ARMHOME)\bin\armcpp.exe LD=$(ARMHOME)\bin\armlink.exe ELFTOOL=$(ARMHOME)\bin\fromelf.exe
CFLAGS=-apcs/ropi/rwpi LFLAGS=-ropi -rwpi
OBJS=main.o tmpl.o
all: $(OBJS) $(LD) $(LFLAGS) $(OBJS) -o main.elf $(ELFTOOL) -c -s main.elf -o main.map $(OBJS): $(CPP) $(CFLAGS) -c $(@:.o=.cpp) -o $@
检查产生的main.map可以看到如下的反汇编结果 __D C$$dtor 0x00008934: e59f0008 .... LDR r0,0x8944 0x00008938: e3a01000 .... MOV r1,#0 0x0000893c: e0800009 .... ADD r0,r0,r9 0x00008940: eafffde1 .... B __dt__7FooInstFv ; 0x80cc $d 0x00008944: 00000064 d... DCD 100 __D $a C$$dtor 0x00008948: e59f0008 .... LDR r0,0x8958 0x0000894c: e3a01000 .... MOV r1,#0 0x00008950: e0800009 .... ADD r0,r0,r9 0x00008954: eafffddc .... B __dt__7FooInstFv ; 0x80cc $d 0x00008958: 00000064 d... DCD 100 这段代码被__cpp_finalise_dtors调用,可以看出对于同一个Foo对象析构了两次.
解决的方法也很简单.去掉//bug下面的那句,打开//solution下面的那句就可以了. ADS的这几个bug很让人头痛.其它的编译期能出错的bug还好说,这两个bug编译的时候不声不响的,运行时就出错了,一开始简直无从下手. 04 Januar <<飞>>是昨天晚上无聊的时候在CCTV6看的一个片子,国产片,场景,故事都很简单,我很喜欢.今天上google搜了一下,一无所获,大概看过的人不多吧,比不得时下走红的大片们,不过我很喜欢.
<<飞>>讲的是一个农村的孩子,从小就有一个造飞机的梦想,从小就被村里人认为有病.后来青梅竹马的女孩嫁给了别人,老大不小讨不到媳妇,梦想却从未放弃.
<<飞>>的画面也很不错,看起来很优美.说实话国产电影我喜欢的不多,这部是个例外.
梦想,从未放弃. 12 Juli 声明一个类,只声明一个带有默认参数的构造函数, 然后实例化该类的实例数组的时候. 该构造函数被调用,但是没有传入默认参数,猜想是编译器作者在数组实例化过程中调用构造函数没有压入参数导致,具体例程我将在最近两天给出.
我也终于发现了商用编译器的bug了. :) 13 Mai 9. 在Java中嵌入和扩展Jython 9.1 嵌入Jython 在org.python.util包中的三个类提供了在Java中嵌入Jython的必要手段,这三个类是: PythonInterpreter, InteractiveInterpreter 和 InteractiveConsole. 前面提到的顺序也是这三个类的继承顺序. PythonInterpreter + initialize + get + set + exec + eval + execfile + getLocals + setLocals InteractiveInterpreter(PythonInterpreter) + runcode + runsource + interrupt Interactiveconsole(InteractiveInterpreter) + push + interact + raw_input 9.1.0 PythonInterpreter 嵌入Jython经常被认为就是在Java应用程序中使用Java类org.python.util.PythonInterpreter的一个实例.在Jython的安装包jython.jar中包含了这个类.嵌入它只需要两行: import org.python.util.PythonInterpreter; PythonInterpreter interp = new PythonInterpreter(); 9.1.1 intialization Jython的运行环境依赖于一些属性,例如: python.home, python.path 和 python.security.respectJavaSccessbility, 通常在启动的时候从注册表文件中读取或者在命令行选项中指定.在嵌入Jython的时候可以在创建解释器实例之前指定这些属性,因此这是一个静态方法. 9.1.2 Properties and Intialization 应该在创建PythonInterpreter实例之前先初始化它,也就是设置它的一些属性.这个静态函数的原型是这样 public static void intitialize(Properties preProperties, Properties postProperties, String[] argv) preProperties常被设置为System.getProperties(),这样它就包含了Java的-D命令行开关. postProperties常被指定为一个新的包含许多已经加入的入口(entry)的java.util.Properties实例.argv将会传给Jython的sys.argv. Properties props = new Properties(); props.put("python.home", "/usr/local/jython-2.1"); // *nix //props.put("python.home", "c:\\jython2.1"); // windows PythonInterpreter.initialize(System.getProperties(), props, new String[0]); 初始化PythonInterpreter也会处理Jython的注册表文件(如果能找到的话),处理顺序依次是preProperties, registry file 和 postProperties. 在org.python.demo中有一个嵌入Jython解释器的例子. // file: Embedding.java package org.python.demo; import java.util.Properties; import org.python.util.PythonInterpreter; import java.util.Enumeration; public class Embedding { protected PythonInterpreter interp; public static void main(String[] args)) { Embedding embed = new Embedding(); embed.initInterpreter(args); embed.test(); } protected void initInterpreter(String[] argv)) { // Get preProperties postProperties, and System properties Properties postProps = new Properties(); Properties sysProps = System.getProperties(); // set default python.home property if (sysProps.getProperty("python.home")==null) sysProps.put("python.home", "c:\\jython-2.1"); // put System properties (those set with -D) in postProps Enumeration e = sysProps.propertyNames(); while ( e.hasMoreElements() ) { String name = (String)e.nextElement(); if (name.startsWith("python.")) postProps.put(name, System.getProperty(name)); } // Here's the initialization step PythonInterpreter.initialize(sysProps, postProps, argv); //instantiate- note that it is AFTER initialize interp = new PythonInterpreter(); } public void test() { // Print system state values to confirm proper initialization interp.exec("import sys"); interp.exec("print"); // Add empty line for clarity interp.exec("print 'sys.prefix=', sys.prefix"); interp.exec("print 'sys.argv=', sys.argv"); interp.exec("print 'sys.path=', sys.path"); interp.exec("print 'sys.cachedir=', sys.cachedir"); interp.exec("print"); // Another blank for clarity } } 编译上面的类Embedding,选择一个工作目录,在其中创建org/python/demo目录,创建{working derectory}/org/python/demo/Embedding.java 然后使用下面的命令: javac -classpath /path/to/jython.jar org/python/demo/Embedding.java java -classpath /path/to/jython.jar;. org.python.demo.Embedding 也可以 java -Dpython.cachedir="newcache" -Dpython.path="d:\devel\jython" -classpath "c:\jython-2.1\jython.jar";. org.python.demo.Embedding *sys-package-mgr*: processing new jar, 'C:\jython-2.1\jython.jar' *sys-package-mgr*: processing new jar, 'C:\jdk1.3.1\jre\lib\rt.jar' *sys-package-mgr*: processing new jar, 'C:\jdk1.3.1\jre\lib\i18n.jar' *sys-package-mgr*: processing new jar, 'C:\jdk1.3.1\jre\lib\sunrsasign.jar' sys.prefix= c:\jython-2.1 sys.argv= [] sys.path= ['.', 'c:\\jython-2.1\\Lib', 'd:\\devel\\jython'] sys.cachedir= c:\jython-2.1\newcache 9.1.3 解释器示例 PythonInterpreter除了默认的构造外还有其它的构造器(constructor)允许设置解释器的名字空间和系统状态(system state).原型如下: public PythonInterpreter() public PythonInterpreter(PyObject dict) public PythonINterpreter(PyObject dict, PySystemState systemState) dict会成为解释器的名字空间,一般来说会使用org.python.core.PyStringMap对象,PyDictionary或者其它的类字典(dictionary-like)对象也可以,但是如果没有充足的理由,建议使用PyStringMap. // the required imports import org.python.core.*; import org.python.util.PythonInterpreter; // Assume the interpreter is already intitialized PyStringMap dict = new PyStringMap(); dict.__setitem__("Name", new PyString("Strategy test")); dict.__setitem__("Context", Py.java2py(new SomeContextClassOrBean())); PythonInterpreter interp = new PythonInterpreter(dict); 使用PySystemState对象可以设置sys.path,关于PySystemState后面会有更多解释,现在只需要了解它在Jython内部对应的是sys模块即可. PyStringMap dict = new PyStringMap(); dict.__setitem__("A", new PyInteger(1)); PySystemState sys = new PySystemState(); sys.path.append(new PyString("c:\\jython-2.1\\Lib")); sys.path.append(new PyString("c:\\windows\\desktop")); sys.path.append(new PyString("d:\\cvs")); // instantiate with namespace and system state objects interp = new PythonInterpreter(dict, sys); 如果需要嵌入多个解释器的时候,可以让它们共享一个PySystemState对象. 9.1.4 设置输出流和错误流(Output and Error Streams) PythonInterpreter有两个函数.setOut和.setErr 他们都接受一个参数,可以是java.io.OutputStream, java.io.Writer或者是任何的类文件(file-like)org.python.core.PyObject对象. // file: ErrorRedir.java package org.python.demo; import org.python.demo.Embedding; import java.io.*; public class ErrorRedir extends Embedding { public static void main(String[] args)) { ErrorRedir erd = new ErrorRedir(); erd.initInterpreter(args); erd.test(); } public void test() { // Redirect errors to a file try { interp.setErr(new FileWriter(new File("errors"))); } catch (IOException e) { e.printStackTrace(); } interp.exec("assert 0, 'This should end up in a file.'"); } } 9.1.5 PySystemState Jython中,sys模块包含了系统状态的信息.在Jython中的import sys在Java中就意味着: import org.python.core.* PySystemState sys = Py.getSystemState(); 这里要注意的是如果你使用了多个内嵌Jython解释器的实例,PySystemState的改变会反映到每个解释器实例. Jython的PySystemState类(sys模块)也包含了三个加载类有关的方法: add_package, add_classdir 和 add_extdir. 当在Java中嵌入Jython的时候这些方法非常重要,因为很多Java应用都有他们自己的类加载器(classloader).如果应用程序的类加载器和Jython的不同,Jython就可能不能正确的找到Java包. add_package方法在Jython的包管理器里面放置了一个特别的Java包.如果A公司有一个有自己的类加载器的嵌入Jython的应用程序,被嵌入的解释器可能不能正确的定位类似com.A.python这样的Java包.这个时候就需要add_package方法. import org.python.core.*; PySystemState sys = Py.getSystemState(); sys.add_package("com.A.python"); add_package方法并不引入(import)或者加载(load)包,而是由应用程序的类加载器来做.add_classdir和add_extdir也是做类似的工作.例如: import org.python.core.*; PySystemState sys = Py.getSystemState(); sys.add_classdir("/usr/java/devel/"); import org.python.core.*; PySystemState sys = Py.getSystemState(); sys.add_extdir("/usr/java/lib/"); 关于这三个方法的使用,有个很好的例子,请参见随着Jython发布的org.python.util.PyServerlet. 9.1.6 使用解释器. exec方法可以执行一个包含Python代码的字符串或者一个预编译(pre-compiled)代码对象.传给exec方法的必须是一个完整的代码片断. execfile方法可以执行一个文件或者InputStream对象.这个方法有三个重载版本,第一个接受一个指定要执行的文件名的字符串作为参数,第二个接受一个InputStream对象,因为没有名字联系到InputStream,错误消息将显示<iostream>在错误消息定位文件中(原文为: error messages will show <iostream> in the file name location of error messages).第三个方法接受一个InputStream对象和一个String对象,这个字符串指定错误消息的文件名.Java函数原型如下: public void execfile(String s) public void execfile(java.io.InputStream s) public void execfile(java.io.InputStream s, String name) eval方法和exec方法有三个差别:eval总是将交给它评估(evaluate)的表达式的结果作为org.python.core.PyObject -- Jython中对应Java中的java.lang.Object的类 -- 返回,er exec和execfile总是返回void.目前解释器的eval方法只能接受代码字符串,而exec可以接受字符串或者经过编译的代码对象.最后,解释器的eval方法只能对表达式求值,不能含有赋值和声明,这一限制和lambda是一致的,而exec可以运行任何Jython代码.实际上解释器的eval调用的是Jython的内置函数eval.下面两行是等价的: // The interpreter's eval shortcut interp.eval("1 or 0") // The interpreter's eval() // The built-in version __builtin__.eval(new PyString("1 or 0"), interp.getLocals()) 9.1.7 为将来使用编译代码对象 使用Jython的内建函数compile.需要三个步骤:引入需要的类(org.python.core包),创建一个java.lang.String实例,然后将String编译为code()对象. // Import required classes (PyCode and __builtin__) import org.python.core.*; // Create a java.lang.String String s = "print 'Hello World'"; // compile with "<>" for the file-name, and "exec" for type of object PyCode code = __builtin__.compile(s, "<>", "exec"); // exec with interpreter. Note: no return object interp.exec(code); 内建的compile函数需要三个参数,第一个PyString传入代码,第二个是文件名(用于输出错误消息),和模式,模式可以是exec,eval或者single(如果只是一条单独的语句), import org.python.core.*; String s = "1 and 0 or 10"; PyCode code = __builtin__.compile(s, "<>", "eval"); // Fetch the interpreter's local namespace PyCode locals = interp.getLocals(); // use __builtin__.eval with interp's locals PyObject o = __builtin__.eval(code, locals); 9.1.8 在解释器中处理异常 # in Jython try: f = open("SomeNonExistingFile") except IOError: e, i, tb = sys.exc_info() print e, "\n", tb.dumpStack() // in Java try { interp.exec("f = open('SomeNonExistingFile')"); } catch (PyException e) { e.printStackTrace(); } 可以在解释器的主循环中加入如下的结构 try { interp.exec("f = open('SomeNonExistingFile')"); } catch (PyException e) { if (Py.matchException(e, Py.AttributeError)) { //handle Jython's AttributeError here } else if (Py.matchException(e, Py.IOError)) { //handle Jython's IOError here } } 9.1.9 set方法和get方法 set方法和get方法从解释器的本地名字空间中取出或者设置一个对象.需要和getLocals和setLocals这一对函数区别.set和get所指的名字空间一个由locals变量标识的PyStringMap对象.getLocals和setLocals在后面会提到. 类PythonInterpreter的set方法有两个版本,都是把解释器之外的一个对象绑定到解释器中的一个Jython标识符.原型如下: public void set(String name, Object value) public void set(String name, PyObject value) 如果传入的第二个参数是一个Java的Object对象,解释器会将这个对象转换为合适的Jython类型.转换规则可以参见第二章相关内容.注意对于Java原生类型来说,下面这样的写法会有编译错误 interp.set("I", 1); interp.set("C", 'c'); 应该使用他们在java.lang中的对应物,如下所示: interp.set("I", new Integer(1)); interp.set("C", new Character('c')); get方法从解释器中获得一个对象,这个方法也有两个原型: public PyObject get(String name) public Object get(String name, Class javaclass) 关于get的第二个版本示例如下: interp.set("myStringObject", "A string"); String s = (String)interp.get("myStringObject", String.class); 还有另一种方法可以从Py*对象转换为Java对象,这就是__tojava__方法.PyObject有一个特殊的方法,叫做__tojava__,这个方法需要一个Java class作为参数,返回转换为该类型的对象.如果转换不能进行,它会返回Py.NoConversion.对Py.NoConversion值做任何类型转换都会抛出ClassCastException异常.所以,可以在类型转换前先检查是否返回的是Py.NoConversion或者将转换操作放在try/except结构中. 在此处有一个例子,设计两个Java文件和一个Jython文件,由Jython类继承了Java类,然后通过运行Jython脚本生成类实例,Java从Jython解释器得到类实例并调用了其中的函数,这个例子很好的诠释了Java和Jyhton的互动,演示了如果通过Jython脚本来进行快速的原型测试. 9.1.10 getLocals方法和setLocals方法 Locals意味着解释器的本地名字空间,上面提到的set和get方法只是操作的本地的映射(mapping)对象中的键和值.而setLocals和getLocals允许访问整个名字空间映射(mapping)对象.getLocals和setLocals返回或需要的是一个类字典(dictionary-like)的PyObject,通常都是org.python.core.PyStringMap. 9.1.11 imp和顶层(Top-Level)脚本 Top-Level脚本指 if __name__ == '__main__', __main__是自动由Jython添加的,但是如果嵌入Jython的时候,你必须显式的添加__main__如果你希望这种方法能正常工作的话.可以通过两种方法来实现: PyModule mod = imp.addModule("__main__"); interp.setLocals(mod.__dict__); // Set __name__ PyStringMap dict = new PyStringMap(); dict.__setitem__("__name__", new PyString("__main__")); interp.setLocals(dict); 类imp实现了Jython的import机制,方法addModule加载一个模块然后返回PyModule对象,同时将module的名字放在已经加载的模块列表(sys.modules)中,更多细节参加本章最后一小节:扩展Jython 9.2 嵌入InterractiveInterpreter InteractiveInterpreter是PythonInterpreter的一个子类,增加了runcode,runsource和interrupt几个方法.提供了两个重要的行为:如果有异常在runcode或者runsource方法中发生,它会陷入(trap)而避免致命(fatal)错误,是的解释器可以继续,解释器会打印出错误,告诉用户发生了什么.runsource返回一个布尔值来指出源字符串的完整性,这一特性可以用来决定要显示哪种提示符和何时重置语句缓冲.在这一小节也有一个详细的例子可以参考. 9.3 嵌入InteractiveConsole InteractiveConsole增加了三个主要方法:interact,raw_input和push.方法interact是对Jython解释器的一个模拟.push将一个不是\n结束的字符串送进解释器,该方法返回布尔值,含义同runsource.同样,这一小节也有一个例子,简单易懂. 9.4 扩展Jython 扩展Jython的意思是说使用Java开发Jython模块.这里Jython模块指的是其行为像是Jython模块的Java类.虽然Jython也可以使用普通的Java类,但是Jython的语意还是和Java有一些差异,例如命名参数(keyword parameter).使用Java开发Jython模块和开发普通Java类的主要区别在于接口ClassDictInit,与之相关的classDictInit方法,__doc__字符串和PyException.本节使用一个简单的例子演示了这些差异. 9.4.1 ClassDictInit 用Java开发的Jython模块如果从ClassDictInit继承就可以控制模块的__dict__属性,实现了接口ClassDictInit接口的类必需要有如下的方法: public static void classDictInit(PyObject dict) Jython会在类初始化的时候调用classDictInit方法.可以在这个时候设置__doc__字符串,并在字典中删除自己的入口.这样做在开发一个复杂的模块的时候可以灵活的控制可见性.还有一种手段可以控制Java实现在Jython中的可见性,有个叫做org.python.core.PyIgnoreMethodTag的异常,这个异常从来不会被真正的抛出,但是如果一个Java方法声明抛出这个异常将会自动的在Jython中不可见. 9.4.2 __doc__字符串 module的__doc__通过定义一个静态的PyString成员__doc__来实现 静态方法的__doc__通过添加一个静态的PyString成员__doc__methodName来实现. 9.4.3 异常(Exceptions) 抛出异常需要两个参数,一个是真正的Jython异常,一个是异常信息: throw PyException(Py.ValueError, "Invalid Value"); 9.4.4 参数(Parameters) Jython的函数的参数传递方式包括顺序参数,命名参数,缺省值和统配符.这些都可以用Java来模拟.下面的方法原型允许Java方法处理顺序参数(positional)和命名参数(keyword): public PyObject MyFunction(PyObject[] args, String[] kw); args数组保留所有的参数值,kw数组只保留特定的关键字,如下的调用: MyFunction(1, 2, D=4, C=9) args和kw数组会获得如下的值: args = [1, 2, 4, 9] kw = ["D", "C"] 类org.python.core.ArgParser提供了容易的分析参数方法,这个类有以下四种形式的构造函数: public ArgParser(String funcname, PyObject[] args, String[] kws, String p0) public ArgParser(String funcname, PyObject[] args, String[] kws, String p0, String p1) public ArgParser(String funcname, PyObject[] args, String[] kws, String p0, String p1, String p2) public ArgParser(String funcname, PyObject[] args, String[] kws, String[] paramnames) Jython Method: def test(A, B, C=2) def addContact(name, addr, ph=None) Java implementation: public static PyObject test(PyObject[] args, String[] kws) { ArgParser ap = new ArgParser("test", args, kws, "A", "B", "C"); } public static PyObject addContact(PyObject[] args, String[] kws) { ArgParser ap = new ArgParser("addContact", args, kws, new String[] {"name", "addr", "ph"}); } 参数的值可以从ArgParser实例的方法获得,下面列出get*方法,get*方法有一个或者两个参数,两个参数的版本用来获得默认值,注意参数开始的位置是0,而不是1. public String getString(int pos) public String getString(int pos, String def) public int getInt(int pos) public int getInt(int pos, int def) public PyObject getPyObject(int pos) public PyObject getPyObject(int pos, PyObject def) public PyObject getList(int pos) 下面是一个Jython方法和它的Java完整实现: def test(A, B, C=2) # In Jython public static PyObject test(PyObject[] args, String[] kws) { ArgParser ap = new ArgParser("test", args, kws, "A", "B", "C"); int A = ap.getInt(0); // or ... // String A = ap.getString(0); // PyObject A = ap.getPyObject(0); // PyTuple A = (PyTuple)ap.getList(0); String B = ap.getString(1); // or... // int B = ap.getInt(1); // PyObject B = ap.getPyObject(1); // PyObject B = ap.getList(1); int C = ap.getInt(2, 2); // first 2=position, second 2=default value } 9.4.5 在Java中引入(Import)Jython模块 在Java中引入Jython模块通常使用__builtin__.__import__方法,这个方法有以下四种原型: public static PyObject __import__(String name) public static PyObject __import__(String name, PyObject globals) public static PyObject __import__(String name, PyObject globals, PyObject locals) public static PyObject __import__(String name, PyObject globals, PyObject locals, PyObject fromlist) 9.4.6 和PyObject协调工作 在Java中调用Jython类或者使用Java开发Jython模块都需要使用Jython的特殊方法,特殊方法指哪些由两个下划线开始和结束的方法(参见第7章).Jython的动态操作意味着finding,geting,seting和calling属性(详见第7章). __findattr__返回对象属性, __finditem__返回序列或者字典中和特定键联系的值. public PyObject __finditem__(PyObject key) public PyObject __finditem__(int index) public PyObject __finditem__(String key) public PyObject __findattr__(String name) public PyObject __findattr__(PyObject name) 下面是一个例子: PyObject random = __builtin__.__import__("random"); random.__findattr__("randint").__call__(new PyInteger(10), new PyInteger(20)); invoke方法相当于myPyObject.__getattr__(name).__call__(args, keywords) ,下面是它的原型: public PyObject invoke(String name) public PyObject invoke(String name, PyObject arg1) public PyObject invoke(String name, PyObject arg1, PyObject arg2) public PyObject invoke(String name, PyObject[] args)) public PyObject invoke(String name, PyObject[] args,, String[] keywords)) 下面是例子: PyDictionary dct = new PyDictionary(); dct.__setitem__(new PyString("G"), new PyInteger(1)); dct.__setitem__(new PyString("D"), new PyInteger(2)); dct.__setitem__(new PyString("A"), new PyInteger(3)); dct.__setitem__(new PyString("E"), new PyInteger(4)); dct.__setitem__(new PyString("B"), new PyInteger(5)); PyObject keys = dct.invoke("keys"); 在上一个例子中使用返回的keys需要十分小心,一位内PyObject.__len__可能返回错误的值,只有通过 一下方法才是安全的:逐个测试index知道返回无效的index. PyObject key; for (int i = 0; (key = keys.__finditem__(i)) != null; i++) { System.out.println("K: " + key + ", V: " + dict.__getitem__(key)); } 9.4.7 用Java开发Jython类 使用Java类模拟Jython模块的时候,通常用静态类方法来实现Jython的模块中的方法.模拟Jython类使用静态内嵌(inner)类,最好从合适org.python.core.Py*类派生,所有的类都应该是PyObject的子类并且实现了__findattr__,__setattr__和__delattr__方法.一个映射(Mapping)类应该是PyDictionary或者PyStringMap的子类并且实现__finditem__,__setitem__,__delitem__和其它映射相关方法. 9.4.8 将Java类作为内建Jython模块 注册表键python.modules.builtin允许我们将Java开发的Jython模块作为内建模块加入Jython,这个键的值是以逗号分隔的一列入口.用法有 name Java类的名称,假设类在org.python.modules包中. name:class class指出了类所在的位置. name:null 删除一个内建模块,如果要删除os模块,使用 python.modules.builtin=os:null 目前只能通过注册表文件和post-properties(在initialize方法中)设置,将来会支持-D的命令行. 11 Mai 0 Java安全体系概述 从JDK 1.0开始Java就实现了一套安全架构,主要用于Applet. 在这种体系下Java Code的执行环境被严格划分为两个部分,本地代码可以访问计算机的所有资源,而远端代码(Romote Code: 主要是Applet)只能运行在严格限制的沙箱里面.安全管理器(Security Manager)作为一个子系统来决定哪些资源允许沙箱中的程序访问. JDK 1.1引入了"签名Applet"的概念,一个被信任签名的Applet被当作和本地代码具有同等权限,可以访问全部的本地资源. JDK 1.2做了很多改进.首先,无论本地代码还是远端代码(remote code)现在都服从于安全策略.安全策略为各种签名者和来源定义了一组许可(permission),可以由用户和系统管理员来配置各种许可.每个许可(permission)指定允许访问只用特定的资源,例如读或写一个特定的文件/目录或者可以连接到指定的地址和端口... 运行时系统将代码组织为不同的域(domain),每个域对应一组许可,在这个域中的类的实例都受这个域指定的许可的限制. 1. 控制你的Application 首先要明确的是,本地应用程序运行的时候,安全管理器(security manager)并没有被安装.所以,对于应用程序来说,默认是可以访问所有的资源,这一点和Applet不同.要启动安全管理器就是在启动命令行加上 -Djava.security.manager.默认加载的系统策略文件授予了所有代码访问一些通用属性的许可.这个文件是${jre_home}\lib\security\java.policy.在命令行上给定 -Djava.security.manager 启动应用程序,系统会首先加载${jre_home}\lib\security\java.security 在这个文件中搜索policy.url可以看到如下的两行 policy.url.1=file:${java.home}/lib/security/java.policy policy.url.2=file:${user.home}/.java.policy 在这两行加载了默认的策略文件,我们也可以编辑自己的策略文件然后添加到java.security中使应用程序应用我们的安全策略.除此以外还有另一种指定我们自己的安全策略文件的方法,就是在命令行上使用 -Djava.security.policy=mypolicy 选项. 如果熟悉策略文件的语法,可以自己用文本编辑器编辑,推荐使用工具policytool,这是jre提供的一个专门用来编辑策略文件的工具. 2. 可信(Secure)代码和交换文件需要使用的API和工具 为了保证代码的安全性,需要确定代码或文件的来源,需要提供者进行数字签名.可以使用keytool或者security API来产生公钥/私钥对.为了验证公钥的确来自发布者,需要数字证书(certificate),数字证书由被信任的第三方提供.公钥/私钥对和证书存储在一个密码保护的数据库里,叫做keystores. 2.1 对代码签名并赋予许可 2.2 交换文件 2.3 产生和校验签名 3. 实现你自己的许可 本节中有一个例子,参见http://java.sun.com/docs/books/tutorial/security1.2/userperm/index.html 在代码中检查是否具有某种许可: 1. 调用System.getSecurityManager()来得到当前安装的security manager. 2. 如果返回结果不为null,可以进一步查询是否具有需要的许可.java.security.AccessController有个方法叫做doPrivileged,可以临时的提高某种权限来获得特定资源的访问许可,从而可以将对于特定资源的访问限定在某个类,并不对整个应用放开,只有调用特定的类才能访问特定的资源,详见New Privileged Block API相关文档. 3. java.security.Permission和java.security.BasePermission这两个类对于控制资源访问权限很重要.java.security.SecurityManager的方法checkPermission()接受的参数就是Permission极其子类.具体参见Java文档的java.security包部分. 4. 这个例子最后还详细描述了三个角色(框架开发者,资源访问类开发者和使用者)需要做的事情. 参考文献: http://java.sun.com/docs/books/tutorial/security1.2/TOC.html 09 Mai 3. 错误和异常 3.1 Jython异常 Jython异常类定义在org.python.core.exceptions.因为Jython可以使用Java Class(es),所以Jython也可能抛出Java异常. 3.2 异常处理 在CPython2.1中新加了sys.excepthook机制,可以允许设置一个可调用(callable)对象.当一个异常发生后,如果找不到匹配的except子句,在退出系统之前会传递给sys.excepthook.这样就可以在程序结束前做任何需要的事情. Jython中的try语句有两种形式: try/except/else 和 try/finally try: code-black except [expression [, target]]: code-block [else: code-block] >>> try: ... raise SyntaxError, "Bad Syntax" ... except SyntaxError, target: ... print target ... Bad Syntax try: code-block finally: code-block 3.3 raise 语句 raise [expression [, expression [, expression ]]] 或者可以写为(可读性更好): raise [type [, value [, traceback]]] type为实际抛出的异常类,也可以是一个字符串或者一个异常类的实例.value会作为构造参数传递给异常类.如果type已经是一个实例,则value不会有任何效果,这个时候Value必须为None.传递给异常类构造的参数个数取决于value是否为一个tuple,一个list,dictionary,number或者任何其他不是tuple的类型都会作为一个参数来传递,只有tuple会作为一个参数序列传递.如果存在可选的第三个参数,那么它必须是一个traceback对象.如果raise后面不加任何参数,则会再次抛出同一范围内的最后抛出的那个异常. 3.4 Tracebacks 调用sys.exe_info()可以返回三个值,分别是 type, value 和 traceback. traceback.exc_lineno()可以返回抛出异常的行号. traceback.extract_tb()可以返回整个traceback. # file: raise.py import sys import traceback try: raise SyntaxError, "Bad syntax" except: exc_type, exc_value, exc_tb = sys.exc_info() print "The type of exception is:", exc_type print "The value supplied to the exception was", exc_value print "The type of exc_tb is:", type(exc_tb) print "The line where the exceptions was raised is", print traceback.tb_lineno(exc_tb) print "The (filename, line number, function, statement, value) is:" print traceback.extract_tb(exc_tb) The results from running "jython raise.py" are: The type of exception is: exceptions.SyntaxError The value supplied to the exception was Bad syntax The type of exc_tb is: org.python.core.PyTraceback The line where the exceptions was raised is 6 The (filename, line number, function, statement, value) is: [('raise.py', 6, '?', 'raise SyntaxError, 'Bad syntax"')] 3.5 assert语句和__debug__变量 assert语句也可以抛出异常. assert expression [, expression ] 如果第一个expression为false,则抛出AssertionError异常,并将第二个experssion作为参数传给它的构造.可以通过设置__debug__为0来进制assert.将来的版本中__debug__变量可能会是个只读变量,并且监视器启动的时候会支持一个-O选项来禁止assert. 3.6 The Warings Framework Jython2.1 引入了warning体系,warning代表一个不建议使用的语言特性.要使用warning,你应该import这个模块,warning模块有一个叫做warn()的方法. # file "warn.py" def oldFunction(): import warnings warnings.warn('"oldFunction" is deprecated. Use "newFunction"') >>> import warn >>> warn.oldFunction() /home/rbill/warn.py:3: UserWarning: "oldFunction" is deprecated. Use "new Function" warnings.warn('"oldFunction" is deprecated. Use "newFunction"') .warn还有可选的第二个参数和第三个参数,第二个参数指出warning的子类,第三个参数叫做stacklevel,支出这个warning会网上传几层. 使用warnings.filterwarning函数可以控制warning的行为和显示. # file: warntest.py import warnings warnings.filterwarnings(action = 'ignore', module = 'warn') import warn warn.oldFunction() warings.filter有六个参数,依次是: action, message, category, module, lineno 和 append. 只有第一个参数是必需的. action可能的取值为: igore,error,always,default,module或者once. message是一个和warning message匹配的字符串, category指定warings类的一个子类. module限制过滤来自指定的module的warning,它必须是一个字符串,lineno指定匹配的行号,append指出新创建的过滤器会放到已经存在的过滤器序列的最后还是最前面. Python有一个-W的命令行参数来控制warnins的行为,但是Jython还没有实现. 3.7 比较Jython和Java Java使用throw和catch, Java有完整的 try/catch/finally结构. 2. 操作符,类型和内建函数 2.1 标识符(Identifiers) Jython标识符由字母和数字以及下划线组成,第一个字符不能是数字,标识符不能和关键字相同,Jython标识符大小写敏感. 关键字列表:and, as, assert, break, class, continue, def, del, elif, else, except, exec, finally, for, from, global, if, import, in, is, lambda, not, or, pass, print, raise, return, try, while. 2.2 Jython数据对象 Jython从Python继承而来的类型有: integer, long, float, complex, string, tuple, list 和 dictionary 以及其他.但是Jython没有简单类型(primitive type),所有的数据类型都是org.python.core中的一个类. PyInteger, PyLong, PyFloat, PyComplex, PyString, PyTuple, PyList, PyDictionary等.使用内建函数type()可以得到一个对象的类型.在org.python.core中有很多Py前缀的类,这些类有很多公有方法,其中有一部分是为了给Java调用而准备的. 本章并不讨论所有的Py前缀的类,而只是讨论Jython的基本数据对象,四个数字(numeric)对象,三个序列(sequence)对象,两个mapping对象和Jython的None对象. 2.2.1 Numeric Objects 2.2.1.1 PyInteger: 可以认为是Java的原始int类型(32bits +/-2147483647),超出范围溢出会抛出异常. 2.2.1.2 PyLong: 后缀为L/l的数字,只受有效内存大小的限制.推荐使用大写(L) 2.2.1.3 PyFloat: 可以认为是Java的原始double类型(64bits) 2.2.1.4 PyComplex: r(real)+i(imaginary)j, r和i都是float.如 1.3 + 0.2j . PyComplex两个成员变量, x.real, x.imag, 一个实例方法 .conjugate(取共轭) 有趣的是数字对象都是不可修改的(immutable),如下所示 >>>x = 10 # create our immutable variable >>>id(x) # get the id of x 2284055 >>>x = x + 1 # an assignment is required to add the 1 >>>id(x) # check x's new id 4456558 对于布尔(Boolean)表达式来说,所有数值上等于0的数字都是false. 0, 0L, 0.0, 0.0 + 0.0j Jython有这四种数字类型,但是这并不是Jython所能使用的所有数字类型,Java的卢斯行可以不加修改的在Jython中使用.只需要import java,就可以使用你需要的类型了: >>>import java >>>l = java.lang.Long(1000) >>>print l 1000 >>>l.floatValue() # invoke Java instance method 1000.0 2.2.2 序列(sequence)对象 Jython的序列对象包括PyString, PyTuple, PyList.序列,就是一个有序数据集合(ordered sets of data),区别只是他们所持有的数据.PyString持有字符数据,PyTuple和PyList可以持有任何类型的对象.String和tuple是不可改变的,mutable是可改变的.使用内建函数len()可以得到序列对象的长度.序列对象都可以用object[index]的方式访问.index从0开始,如果index为负,则表示从后往前,-1是最后一个.序列对象可以被切片:object[from:to](包含object[from]不包含object[to],左闭右开区间),from和to都可以被省略,from被省略表示从最初开始,to被省略表示到最末结束(包括最后一个元素).Jython的序列也可以是object[from:to:step]的形式,如下所示: >>> S = 'zahbexlwlvo2 fwzo4rslmd' >>> S[2::2] # this slices from index 2 to the endpoint, steping by 2 'hello world' >>> >>> L = [1,2,3,4,5,6,7,8,9] >>> L[-1:3:-1] # last index to third index, indexes step by -1 [9, 8, 7, 6, 5] 在布尔(boolean)表达式中,空的序列被计算为false,其余为ture. 2.2.2.1 PyString - 字符串对象 Jython的字符串类继承Java的字符串属性,使用给予Unicode 2.0的双字节字符构造.这是Jython中唯一的字符串类型,在CPython中,有8-bit和16-bit类型的包含Unicode 3.0字符的字符串.CPython实现Unicode字符串的时候在前面加上u前缀.为了兼容,Jython支持这种语法.连接两个字符串的操作只需要用空格连接两个字符串(只有字面常量(literrals)字符串可以这样做).反引号(`和~同一个键的字符)有特殊的用途,它可以对一个表达式求值,然后将结果转化为字符串. >>> n = 5 >>> s = `n + 2` >>> s '7' >>> type(s) <jclass org.python.core.PyString at 5471111> 有同样功能的是内建函数repr().需要区别的是另一个内建函数str().通常repr(object) == str(object).但是这两个函数有着不同的功能,所以前面这个等式并不总是成立.在讨论__str__和__repr__的时候我们再次讨论他们. PyString的方法: .capaitalize() 返回首字母大写的串 .center(width) 返回width长度的字符串,将原来字符串放在中间,其他用空格填充. .count(substring [, start [, end]])返回找到substring的个数(在从start到end的左闭右开区间上) .encode([encoding] [, error-handling])返回采用encoding指定编码方式的字符串,如果没有指定则采用默认系统默认编码方式,error-handling可以指定为strict, ignore 或者 replace. .endswtich(suffix [, start [, end]]) 如过原字符串的[start:end]切片以suffix结尾,则返回1,否则返回0. .expandtabs([tabsize]) 返回用tabsize个空格替换\t之后的字符串,tabsize默认为8. .find(substring [,start [,end]]) 返回在原字符串的[start:end]切片中找到substring的第一个字符下标,没有找到则返回-1. .index(substring [,start [,end]]) 同find,只是在找不到的substring的时候抛出ValueError异常. .isalnum() 如果字符串全部为数字和字母,则返回1,否则返回0 .isalpha() 如果字符串全部为字母则返回1,否则返回0 .isdigit() 如果字符全部为数字则返回1,否则返回0 .islower() 如果至少存在一个字母并且存在的所有字母都是小写则返回1,如果没有字母或者有大写字母则返回0 .isspace() 如果全是空白字符则返回1,否则返回0 .istitle() 如果所有单词的第一个字母都是大写并且不是单词第一个字母的字母都是小写则返回1 .isupper() 如果所有字母都是大写返回1,如果没有字母或者有小写字母返回0 .join(sequence) 连接list, tuple, java.util.Vector 或者其他的序列类型, 原字符串作为分隔符. .ljust(width) 返回新的长度为width的字符串,原字符串在最左边,其余部分填充空格. .lower() 返回全部小写的字符串拷贝. .lstrip() 去掉左边多余的空格(原书中有误 -Jerry) .replace(old, new [, maxsplits]) 返回将所有old子串替换为new的字符串拷贝,可选的maxsplits指定最多替换次数. .rfind(substring [, start [,end]]) 同find,只是它返回子串出现的最右位置. .rindex(substring [,start [,end]]) index的最右版 .rjust(width) ljust的右版 .rstrip() lstrip的右版 .split([separator [, maxsplits]) 返回一个list,包含原字符串被separator分割的子串,separator默认为空格,maxsplits指定最多切分次数. .splitlines([keepends]) 返回一个list,将字符串按行分开,keepends默认为false,指定是否保留换行符. .startswith(prefix [, start [,end]]) 参见endswith .strip() 等于.lstrip().rstrip() .swapcase() 返回大小写互换的字符串拷贝. .title() 返回title格式的字符串拷贝,title格式参见istitle .translate(table [,deleteChars]) 原字符串中的字符按table中指定的方式被重新映射,然后删除deleteChars中指定的字符,table是一个256个字符长的字符串,重用string模块的maketrans方法来构造. >>>import string # this loads the string module >>>table = string.maketrans("abc", "def") >>>s = "abcdefg" >>>s.translate(table, "g") # translate "abc" and delete "g" 'defdef' .upper() 返回所有字母都是大写字母的拷贝. 2.2.2.2 PyTuple PyTuple是不可改变的序列,但是它可以持有任何对象,包括可改变的对象( :) 是不是有些混乱? -Jerry )可以使用括号或者不使用括号来构造tuple >>>t = (1,2,3) >>>type(t) <jclass org.python.core.PyTuple at 6879429> >>>t = 1,2,3 >>>type(t) <jclass org.python.core.PyTuple at 6879429> >>> type((1,2,3)) <jclass org.python.core.PyTuple at 6879329> >>>myTuple = (1, "string", 11.5) # tuples can contain any object type 如果只有一个对象,后面需要有一个逗号. >>> t1 = ("element one",) >>> t2 = "element one", >>> type(t1) <jclass org.python.core.PyTuple at 4229391> >>> type(t2) <jclass org.python.core.PyTuple at 4229391> >>> print t1 ('element one',) >>> print t2 ('element one',) PyTuple没有相联系的方法. 2.2.2.3 PyList PyList使用方括号构造,它的方法如下: .append(object) 添加object到list末尾 .count(value) 返回value出现的次数 .extend(list) 将传入的list合并到原list末尾 .index(value) 返回value第一次出现的下标.没有找到则抛出ValueError异常 .insert(index, object) 将object插入到指定的index,其后所有元素后移一位.如果index超过长度则加到最后. .pop([index]) 删除指定的元素并返回它,index默认为最后一个.如果list已经为空或者index指定的位置不存在则抛出IndexError异常. .remove(value) 删除找到的第一个value.如果没有找到抛出ValueError异常 .reverse() 反转list中元素的顺序.无返回值. .sort([cmpfunc]) 对list中元素排序,cmpfunc为比较函数, cmpfunc(x,y), 如果x < y 返回负, x == y返回0, x > y返回正 类似数字类,Jython也可以不加修改的使用Java的其他序列类,例如java.util.vector 注意切片等特性Java类并不支持. 2.2.3 映射对象(Mapping Objects) Jython有两种映射类,或者称为hash类型或者字典(dictionary).映射(mapping)是从不可改变的key到其他对象(value)的连接(connection), Jython两种不同的映射类在于他们使用不同类型的key.映射类也有长度,可以使用len()函数. 2.2.3.1 PyDictionary PyDictionary和CPython中唯一的dictionary相同.另外注意数字作为key的时候的hash算法, PyInteger 1和PyFloat 1.0是不同的,但是在计算hash的时候他们是相同的,被作为相同的key. >>>D = {1: "integer key", 1.0: "float key", 1+0j: "complex key"} >>>D # dump the value of D to prove that there was really only one key {1: 'complex key"} PyDictionary的方法: .clear() 删除所有的key:value对 .copy() 返回字典的浅拷贝 .get(key [,defaultVal]) 返回和key联系的value(如果存在的话),如果value不存在则返回指定的defultVal .has_key(key) 如果字典有这个key返回1,否则返回0 .items() 返回一个包含所有(key,value)拷贝的列表 .keys() 返回一个包含所有key的拷贝的列表 .setdefault(key [, defaultVal]) 返回和key相联系的value,如果key不存在,则插入key:defaultValue, defaultValue默认为None. .update(dict) 用dict中的key:value覆盖原字典中的key:value对,如果原字典中不存在的key则加入. .values() 返回所有value的拷贝的list 2.2.3.2 PyStringMap Jython的PyStringMap类是一种只能使用string做key的字典.这个类的提供不是为了程序员更多的使用它,而是一些内建函数的返回类型,它的存在是因为效率的优势.主要用于namespace,返回它的函数有locals(), globals() 和 vars(). Jython对象的__dict__属性的类型也是PyStringMap. 最后需要说明的是Java的映射类(mapping class)Jython也可以访问. 2.2.4 PyNone 在Java中对应的是null, PyNone继承自PySingleton. PyNone被boolean表达式评估为false. 2.3 操作符 2.3.1 算术运算符(Arithmetic Operators) - (unary) + (unary) ~ (unary, 比特反转,只能用于PyInteger和PyLong, ~x = -(x+1)), + - * **(power-of operator) / % 2.3.2 位运算符(Shift Operators) << >> & | ^ 2.3.3 比较运算符(Comparison Operators) < > == >= <= != <> (same as !=) is ("is" is shortcut for id(x) == id(y) ) is not in ("x in L" 返回true,如果x是序列L的成员) not in 2.3.4 布尔运算符(Boolean Operators) not or and 2.3.5 序列运算符(Sequence Operators) + (连接两个序列) * ( sequence * multiplier, multiplier是一个数字,表示 sequence + 自己多少次 ) 虽然不是操作符,但是字符串的格式化也很重要,Jython支持类似C的printf的格式化字符串 %c 字符 %d 整数(Integer) %e 用小写e科学计数法表示的浮点数 %f 浮点数 %g %e 和 %f 中比较短的一种 %i 整数 %o 无符号八进制数 %r 对象的字符串表示法,由内建函数repr()返回的值 %s 字符串 %u 无符号整数 %x 无符号十六进制数,小写. %E 大写E表示的科学计数法. %G %E 和 %f 中比较短的一种 %X 无符号十六进制数,大写. %% 字符% >>>"Meet the %s at %i o'clock" % ("train", 1) "Meet the train at 1 o'clock" >>>D = {"what":"train", "when":1} >>>"Meet the %(what)s at %(when)i o'clock" % D "Meet the train at 1 o'clock" 2.4 内建(Built-Ins) 2.4.1 自省函数(Introspection Function) type(object) id(object) callable(object) 对于Java的可执行对象并不灵. dir([object]) 返回对象成员名字list,如果没有指定对象则返回当前范围(scope)的名字list vars([object]) 返回一个dictionary,包含了名字和绑定对象的对应关系,对应于对象的__dict__属性,不指定object则同locals() globals() 返回全局名字空间dictionary locals() 返回本地名字空间dictionary 这些属性函数也可以用于Java对象. 2.4.2 数值函数(Numeric Functions) abs(x) divmod(x,y) 返回tuple: (x/y, x%y) hex(x) oct(x) pow(x, y [,z]) 返回x**y如果没有提供z, 如果提供z,返回 x**y % z round(x [,ndigits]) 返回PyFloat, 原数字取ndigits位小数,ndigits默认为0, Jython要求ndigits必须为整数. 2.4.3 类型转换函数(Type Conversion Functions) int(x) long(x) float(x) complex(x) tuple(sequence) list(sequence) coerce(obj1, obj2) 返回一个tuple,包含两个类型相同的值,如果obj1, obj2不可能转型为同一类型,返回None. 2.4.4 文件函数 open(filepath [, mode [, buffer]]) 返回一个文件对象.写二进制文件必须将文件显式的以二进制方式打开.参数buffer目前的实现中被忽略. 2.4.5 序列函数(Sequence Functions) 2.4.5.1 PyString特有的函数. intern(string) 将一个长期存在的字符串放入PyStringMap,可以提高字典搜索的效率. chr(integer) ord(character) unichar(integer) 同chr,这两个函数的存在是为了兼容CPython. unicode(string [,encoding [, errors]]) 用指定的encoding创建一个新的字符串,有效的encodings在Jython Lib目录encoding子目录中可以找到. errors可以为strict, ignore 或者 replace 2.4.5.2 其他序列函数 max(sequence) min(sequence) slice([start, ] stop [, step]) 切片 range([start,] stop [, step]) 返回一个list,所有的参数必须都为整数(PyInteger或者PyLong) xrange([start,] stop [, step]) 返回一个xrange对象. 2.4.6 动态语言函数 comple, apply, execfile, eval 后文会提到 2.4.7 属性工具(Attribute Tools) hasattr, delattr, getattr 这三个函数的参数都是object, attribute. setattr还有可选的第三个参数. isinstance(obj, type) Java对象也可以使用这些函数来操作,不同的地方在于Java对象的属性不能delattr. 2.4.8 函数工具(Functional Tools) filter, map, reduce, zip 后文会提到. 2.4.9 其他函数(Miscellaneous Functions) cmp(x, y) 如果x<y返回-1, 如果x==y返回0, 如果x>y返回1 len(object) repr(object) str(object) reload(module) 你可以运行时改变一个模块的代码,然后重新加载它.( 病毒? --Jerry) raw_input([prompt]) 要求输入,并返回输入的内容 input([prompt]) 和raw_input不同点在于它返回前会先计算输入的内容. hash(object) 返回object的hash值. 2.5 比较Jython数据类型和Java数据类型 Java是静态(static)类型,强(strong)类型语言. Jython是动态(dynamic)类型,强(strong)类型语言. Java和Jython的类型转换 Java类型 Jython类型 Char PyString of length 1 Byte PyInteger Short PyInteger Int PyInteger Long PyInteger Float PyFloat Double PyFloat java.lang.String PyString byte[] PyString char[] PyString PyObject PyObject java class PyJavaClass instance of a Java class PyInstance of the Java class identifyed in instance.__class__ Boolean PyInteger java.lang.object java.lang.object 要创建一个Java Array, 必需使用jarray module. jarray module有两个函数: array, zeros >>> import jarray >>> myJavaArray = jarray.array("abcdefg", "c") >>> myJavaArray array(['a', 'b', 'c', 'd', 'e', 'f', 'g'], char) >>> myJavaArray = jarray.array(['a','b','c','d'], 'c') >>> myJavaArray array(['a', 'b', 'c', 'd'], char) >>> import jarray >>> import java # Required to see the java.lang.Integer class >>> myIntArray = jarray.array([1,2,3,4,5,6,7,8,9], java.lang.Integer) array([1, 2, 3, 4, 5, 6, 7, 8, 9], java.lang.Integer) >>> i = java.lang.Integer(1) >>> import jarray >>> byteArray = jarray.zeros(10, "b") >>> byteArray array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], byte) 类型码(type code) z Boolean java.lang.Boolean c char java.lang.Character b byte java.lang.Byte h short java.lang.Short i int java.lang.Integer l long java.lang.Long f float java.lang.Float d double java.lang.Double 创建Java数组的时候也可以不指定类型,则指定为java.util.Data >>> import java >>> import jarray >>> myDateArray = jarray.zeros(5, java.util.Data) >>> myDateArray array([None, None, None, None, None], java.util.Date) 1. Jython的语法,语句和注释. 1.1 交互控制台(The Interactive Console) Jython 2.1 on java1.5.0_03 (JIT: null) Type "copyright", "credits" or "license" for more information. >>> 如果你设置环境变量JAVA_COMPILER为NONE,JIT显示为null 1.2 以行为划分单位和块缩进的语法(Line Separators and Block Indentation Syntax) 一般来说,Jython认为换行是一句语句结束的标志,以下几种情况例外 分号(Semiconlon) 反斜线(Backslash) 分组开符号(Open groupings) 三个引号(Triple-quotes) 关于后面三种情况有一个声明,目前的交互控制台有一个bug使得后面三种情况在交互控制台下会出错,但是在脚本中是有效的,例如 jython example.py 1.2.1 分号 分号使得我们可以把多个语句(logical line)放在一行(physical line).可以在控制台尝试键入 >>>print "hello"; print "world" 注意print语句会自动插入一个换行符,如果这不是你期望的,可以在print之后加上一个逗号(comma),这样print会添加一个空格而不是换行符. >>>print "hello",; print "world" 1.2.2 反斜线 反斜线作为续行符,但是如前所述,你只能在Jython脚本文件中测试这项特性了. 1.2.3 分组开符号 分组开符号指[],{},()的前半部分.如前所属,只能在Jython脚本文件中测试这项特性. 1.2.4 三个引号 三个引号指"""或者'''.在"""和"""(或者'''和''')之间可以包涵换行符,单引号(')和双引号(")而不需要转义. 1.2.5 代码块 Jython不使用花括号({})来组织和标识一个代码块,而是使用相同的缩进.Jython支持混用空格和tab来区分代码块,但是建议不要这样作,请只使用某一种. 1.3 注释 Jython使用#作为单行注释标识符,#和#之后到换行符之间的字符都被认为是注释. 另一种注释方法是使用匿名字符串常量.如果没有将一个字符串常量赋给一个变量,它就是匿名的,并且对于它出现的名字空间没有影响.你可以使用匿名的三个引号包含的字符串来实现多行注释. 1.4 文档字符串 前面我们提到过自省,文档字符串是出现在函数,方法,和类定义中的匿名字符串常量,你可以在运行时得到它.执行 >>>def foo(): ... """ This is an example doc string""" ... pass ... >>> dir(foo) >>> foo.__doc__ 函数dir()是一个内建函数,可以查看绑定到名字空间(namespace)的名字,返回一个列表(list).foo.__doc__引用了foo的文档字符串. 1.5 语句 语句包括简单语句(simple statements),它只包含一个子句(single clause);复合语句(compound statements),它包含多个子句或者一个与之相联系的代码块. 1.5.1 简单语句 下面是一些例子 1.5.1.1 assert assert语句测试一个表达式是否为true,如果不是就抛出一个异常,如果提供了两个表达式,第二个表达式被作为传递给AssertException的参数,设置__debug__=0,或者在将来版本(嘿嘿)的命令行给出-O选项可以禁用assert. 语法: assert expression [, expression] 1.5.1.2 赋值 把一个对象绑定到一个标识符. assignment-operator: =, +=, -=, *=, /=, **=, %=, <<=, >>=, &=, |=, ^= 语法: variable assignment-operator value 1.5.1.3 break break会终止循环并开始执行循环之后的语句,就是说,如果有else块,也会被跳过. 语法: break 1.5.1.4 continue 语法: continue 1.5.1.5 del del语句从名字空间,列表(list)或者字典(dictionary)中移除一个变量 语法: del identifier 1.5.1.6 exec exec语句执行Jython代码,它要求提供一个表达式,这个表达式代表它需要执行的代码.字符串,打开的文件对象或者代码对象都可以提供给这个表达式.这是exec的第一个参数.exec还可以接受可选的第二和个第三个参数,第二个参数代表代码执行时的全局(global)名字空间字典,第三个参数代表代码执行时的本地名字空间(local namespace). 语法: exec expression [in expression [, experssion]] 1.5.1.7 global global语句告诉解析器(parser)使用全局名字绑定来绑定一个标识符列表(就是跟在global后面的一系列标识符),因为赋值默认是绑定到本地的.下面有两个代码片断. >>>var = 10 >>>def test(): ... print var # try and print the global identifier 'var' ... >>>test() 10 >>> 非常好,下面是另一段. >>>var = 10 >>>def test(): ... print var # try and print the global identifier 'var' ... var = 20 # assign to 'var' in local namespace ... >>>test() Traceback (innermost last): File "<console>", line 1, in ? File "<console>", line 2, in test NameError: local: 'var' >>> 由于赋值语句,var被指定为本地变量,而print语句执行的时候这个本地变量还没有被创建到本地名字空间.这就是需要global的原因. 语法: global identifier [, identifier]* >>>var = 10 >>>def test(): ... global var # must designate var global first. ... print var # try and print the global identifier 'var' ... var = 20 # assign to 'var' in local namespace ... >>>test() 10 >>>print var # check global 'var' 20 >>> 1.5.1.8 import import将定位并初始化被引入的模块,类并绑定的当前名字空间.也可以绑定为不同的名字(和原始名字不同) 语法: import module-name OR from module-name import names OR import module-name as new-name OR from module-name import name as new-name 1.5.1.9 pass pass是一条"什么也不作"的语句,只是一个占位符 语法: pass 1.5.1.10 print print语句对表达式求值,然后如果需要的话将结果转换为字符串,然后将字符串写到sys.stdout或者使用>>语法重定向到一个类文件对象(file-like object).类文件对象(file-like object)是一个定义了write方法的对象. 语法: print [expression] OR print >> fileLikeObject, [expression] 1.5.1.11 raise raise对提供给它的表达式求值然后抛出(raises)一个与之联系的异常(exception) 语法: raise [expression [, expression [ traceback]]] 1.5.1.12 return 语法: return [expression] 1.5.2 复合语句(Compound Statements) Jython使用冒号(colon : )和缩进块的方式表示复合语句. 1.5.2.1 class 语法: class class-name[(base-class-name)]: class-body 1.5.2.2 def def定义函数(function)和方法(method) 语法: def func-name([parameters]): statements 1.5.2.3 for for语句可以有一个else块,如果for没有被break的执行完了,else子句就会被执行.in后面的expression必须能够被计算为一个list. 语法: for variable in expression-can-evaluate-to-a-list: statements [else: statements] 1.5.2.4 if 语法: if expression: statements elif expression: statements else: statements 1.5.2.5 try else子句和finally子句只能有一个出现. 语法: try: statements [except [, expression [, variable]]: statements else: statements] OR [finally: statements] 1.5.2.6 while 语法: while expression: statements 1.6 比较Jython和Java. 1.6.1 assert: Java(1.4及以前)中没有对应的语句. 1.6.2 赋值: 基本类似,有一些差异,后文会提到 1.6.3 break: 相同 1.6.4 continue: 相同 1.6.5 del: Java中没有对应物 1.6.6 exec: Jython的exec用来动态执行Jython代码,而Java的Runtime.exec创建外部进程. 1.6.7 global: Java没有对应物 1.6.8 import: Java的import只有一种形式,并且不能在引入的时候改名. 1.6.9 pass: Java的空语句为 ; 或者 {} 1.6.10 print: Jython中print是一条语句,Java中它是某个类的一个方法. 1.6.11 raise: Java中是throw 1.6.12 return: 相同 1.6.13 class: 语义类似,语法不同 1.6.14 def: Java定义函数更复杂一些 1.6.15 for: Jython的for要求一个序列.而不是Java的(variable, test, increment)方式.Jython用range()和xrange()搭配for来实现传统的(variable, test, increament)的功能,此外,Java的for没有一个else子句. 1.6.16 if: 基本类似,Java使用else if, Jython使用elif 1.6.17 try: 语义类似,需要注意的是Jython中try/except/else和try/finally是不同的两种try语句. 1.6.18 while: 类似,但是Java没有else子句. 0. 简介 Jython是两个非常流行的语言-Java和Python-的联姻.Java有数量庞大的具有良好文档的类库,而Python提供了灵活性,快速开发并且容易理解.在这两个语言之间真是难以抉择,但是现在我们有了Jython. Jython和Java是真正的无缝集成(seamless).其他的可扩展语言,例如Perl或者Python,需要使用特殊的API,或者讨厌的包装类(wrapper classes).普通(arbitrary)的C代码并不能直接应用在Perl或者Python中.但是普通(arbitrary)的Java代码可以直接在Jython中被使用,你可以在Jython中import, 使用, 甚至继承Java类,而不用遵循某种约定或者使用一些特别的API.而且,你可以将Jpython编译为Python的字节码,然后运行在JVM上.你也可以在Java中import,使用甚至继承Python类. 当然它们之间也存在一些缝隙(seam),毕竟它们是两种语言,Jython和Java有许多不同的地方,理解致谢不同点有助于理解Jython.Java是一种富类型(type-rich)的,记过静态类型(static typing)语言,而Jython使用动态类型(dynamic types).Java的package(s)包涵class(es),而Jython有package(s),module(s),class(es)和function(s).Java必需先编译后执行(BeanShell似乎可以把Java当作解释语言来解释-Jerry注),而Jython可以交互(interactively)的运行未编译的脚本,也可以编译为Java字节码(byte-code).Java class执行(implement)如private和protected之类的访问修饰符,Jython只有最小限度的访问限制,没有类似private这样的显式修饰符. 有趣的是Jython和Java之间的差别并没有造成什么困难,反而使得它们成为一对完美的组合.Jython的交互模式是快速测试和探测(explore)Java class的方法,Java的interface和abstract class是非常好的为Jython子类定义协议的方法.Jython的动态类型对于快速建立原型和灵活性非常有帮助,而Java的静态类型有助于增加运行效率和类型安全.她们的组合之所以完美是因为她们的无缝集成. 0.1 什么是Jython Jython是Python的Java实现.Jython是一种完备的(complete)语言,她不是一个Java翻译器(translator),也不是一个python编译器,它是python的Java完整实现.你可以使用Jython实现任何复杂的应用程序.Jython拥有从Python继承而来的相当多的库(library)和模块(module).而且,不想CPython的其他的高级语言,Jython是你可以访问实现它自己的语言(Java)中的所有东西.所以,Jython不仅给了你Python库,而且给了你所有的Java classes. 0.2 为什么使用Jython 0.2.1 无缝访问Java class(es) 0.2.2 效率,综合评估开发,运行,维护效率. 0.2.3 动态类型 0.2.4 自省(introspection)和动态执行,自省是一种运行时发现对象信息的能力.(是否是C++ RTTI概念的扩展?? -Jerry) 0.2.5 第一类(First-Class)函数和函数式编程(Functional Programming).first-class function是一种可以象函数一样被调用,又象变量一样被传递的实体.(又让我联想到C++ STL中的functor -Jerry). Jython也有一些函数化(functional)的工具,例如 list comprehension, lambda, map, filter 和 reduce,也非常容易实现名称的再绑定(name rebinding).Jython也可以当作函数语言来使用. 0.2.6 短的学习曲线. 0.2.7 撰写一次,到处运行 0.2.8 Java安全. 异常处理,沙箱(sandbox),签名(signatures). 0.2.9 清楚的代码 0.2.10 Unicode和i18n 0.2.11 Hotspot和开发效率 第一次蹬长城,箭扣. 5月5日傍晚抵达怀柔西栅子五队. 5月6日从箭扣长城起点九眼楼徒步至箭扣,用时11.5小时. 5月7日从箭扣至慕田峪,用时7小时. Rainny的攻略 02 Mai 如何使用JNI的入门,这么个例子竟然搞了两天,惭愧 HelloWorld.java public class HelloWorld { private native void say_hello(); static { System.loadLibrary("sayhello"); } public static void main(String[] args) { HelloWorld hello = new HelloWorld(); hello.say_hello(); } } --------------------------------------------------------------------------------------------------------- sayhello.c #include <jni.h> #include <stdio.h> #include "sayhello.h" JNIEXPORT void JNICALL Java_HelloWorld_say_1hello(JNIEnv * env, jobject obj) { printf("Hello JNI!\n"); } --------------------------------------------------------------------------------------------------------- env.mak JAVA = C:\developtools\java\jdk1.5.0_03 JAVAC = $(JAVA)\bin\javac JAR = $(JAVA)\bin\jar JAVAH = $(JAVA)\bin\javah INCLUDE = -I$(JAVA)\include -I$(JAVA)\include\win32 CC = C:\developtools\MinGW\bin\gcc --------------------------------------------------------------------------------------------------------- makefile include env.mak CLASSES = HelloWorld.class JAR_FILE = HelloWorld.jar DLL_FILE = sayhello.dll OBJS = sayhello.o CFLAGS = -O2 -Wall -D_JNI_IMPLEMENTATION_ LINKFLAGS = -Wl,--kill-at -shared
.SUFFIXES: .java .class all: $(CLASSES) $(JAR_FILE) $(DLL_FILE) @echo done. .java.class: $(JAVAC) $*.java $(JAR_FILE): $(JAR) cvf $(JAR_FILE) $(CLASSES) $(DLL_FILE): $(OBJS) $(CC) $(LINKFLAGS) -o $@ $? %.o: %.c $(CC) -c $(CFLAGS) $(INCLUDE) -o $@ $< sayhello.c: sayhello.h sayhello.h: $(JAVAH) -o sayhello.h -classpath "$(JAR_FILE)" HelloWorld run: java -cp "$(JAR_FILE)" HelloWorld clean: -del -f *.class -del -f *.o -del -f sayhello.h cleanall: clean -del -f *.jar -del -f *.dll 01 Mai 用VC编译出来的dll 208k, 用gcc编译出来 180k, 我还是喜欢gcc多一点 :) 不过遇到一个问题: 用gcc编译出来的dll没法用,看了一下发现vc编译出来的dll的函数输出名是 _Java_org_keplerproject_luajava_state__1open@8() 而 gcc编译出来的dll的输出名是 Java_org_keplerproject_luajava_state__1open()@8 前面差一个下划线,我自己手动改了luajava.h和luajava.c 给所有的函数前面加了个下划线再让gcc编译,就好了. 不知道是不是我有什么选项没有设置. 难道不是 gcc -shared -o luajava-1.0b4.dll -lliblua.a -lliblualib.a ??? 翻了翻TIJ中的讲JNI的部分,也不知所以然,我就奇怪为什么VC编译出来的就会在函数名前面加上一个下划线,而J2SE5.0也认为需要这个下划线. 希望能尽快找到答案. 下划线的问题我现在能想到的解释是这样: Widnows下的JVM使用VC编译的,所以JVM认识VC的内部名称,而mingw使用的内部名称和VC编译器差一个下划线. 正解应该是使用 .def 或者 mingw 链接的时候使用 -Wl,--kill-at Java_org_keplerproject_luajava_stat__1open这样的名字才是正常的.
|
|
|
|