好记性不如铅笔头

python && jython, 编程

jython学习笔记:基础知识备忘录1

最近在学习【 jython 】这门语言。这里备份下一些基本知识。本文部分内容来源至 IBM 的两篇非常不错的博文,版权属于原作者,但是原文链接已经失效了,作者从网上找了一份网站的备忘,后续把下载链接放上来。

CONTENTS

退出 Jython:

在 Jython 提示符下,输入下列命令:

>>> import sys; sys.exit();

或者,可以按 Ctrl+C 两次。

例子:

#最基本的打印
print 1,2,3;

输出:

1 2 3

Jython 源文件是模块: 

Jython 源文件可以包含一系列要执行的语句。它们还可以包含函数和类定义。 实际上,Jython 源文件可以是模块,而模块不能直接使用,要由其他程序导入。单个源文件可以扮演两种角色。请考虑上一屏中该文件的变体,如下所示:

def fac(x):
     if x <= 1: return 1
     return long(x) * fac(x-1)

if __name__ == "__main__":
     print 1 + 2
     print "Hello" + "Goodbye"
     print fac(3)
     print fac(100)

如果文件被导入到另一个只希望重用fac 函数的程序中,则 if (请参见 if 语句)测试条件下的任何一个语句都不执行。
还要注意,每个模块都有一个名称,从命令行直接执行的名称为 “__main__”。该特性可用于为每个模块创建测试案例。

复数:

>>> x= 1+2j
>>> print x
(1+2j)
>>> print x.real
1.0
>>> print x.imag
2.0

 序列:

序列在 Jython 中是一种抽象概念,因为您不能直接创建序列,只创建从序列派生而来的子类型。任何序列子类型都具有序列的全部函数。序列子类型有几个,如下所示:
字符串 是字符的不变序列(请参见 字符串)。
元组 是任何数据类型的不变序列(请参见 元组)。
范围 是整数的不变序列(请参见 范围)。
列表 是任何数据类型的可变序列(请参见 列表)。

范围

要实现迭代(请参见 for 语句),Jython 使用整数递增的不可变序列。这些序列称为范围。采用两个内置函数很容易创建范围:
range({start,} end {,inc}) 创建一个小范围。 
该范围的所有元素都存在。
xrange({start,} end {,inc}) 创建一个大范围。 
仅在需要时创建元素。

注释

Jython 包含两种形式的注释:
备注(remarks) 是用 sharp (#) 字符引入的注释。# 之后的同一行所有文本都被忽略。备注可以从任何列开始。

文档注释(documentation comments)是紧接在外部块(如模块、类和函数)之后的字符串常量。字符串不改变外部块的行为,而注释可以通过特殊属性 __doc__ 访问以创建块的描述。
例子:

def fac(x):
	"This is a function document"
print fac.__doc__;

输出:

This is a function document

序列例子:

#列表
x=[0,1,2,3,4,5];
print "x:\t",x;
print "x[1]:\t",x[1];
print "x[1:3]:\t",x[1:3];
print "x[2:]:\t",x[2:];
print "x[:3]:\t",x[:3];
print "x[-3:]:\t",x[:-3];
print "x[:-3]:\t",x[-3:];
print "x[:]:\t",x[:];
print "x+x:\t",x+x;
print "x*2:\t",x*2;
print "2*x:\t",2*x;

x=[1,"A"];
print "x:\t",x;
x=[1,[2,"Hello Wrold"],"X",3];
print "x:\t",x;


#元组
x=(1,);
print x;
x=(1,2,3);
print x;
x=(1,"A",2,"B");
print x;
x=(1,"A",("x","y",3),4,"Hello World");
print x;
x=(1,"A",[1,2,3],4,"Hello World");
print x;


#范围
print "range(1,10):\t",range(1,10);
print "range(1,10,3):\t",range(1,10,3);
print "xrange(1,10):\t",xrange(1,10);
print "xrange(1,10,3):\t",xrange(1,10,3);


#字典
x={1:"A",2:"B"};
print "x:\t",x;
print "x[1]:\t",x[1];

#error
#print "x[3]:\t",x[3];

x={"A":"This is a string",2:[1,2,3],"abc":("a","b","c"),4:None};
print "x:\t",x;
print "x[A]:\t",x["A"];
print "x[2]:\t",x[2];
print "x[\"abc\"]:\t",x["abc"];
print "x[4]:\t",x[4];

输出:

x:      [0, 1, 2, 3, 4, 5]
x[1]:   1
x[1:3]: [1, 2]
x[2:]:  [2, 3, 4, 5]
x[:3]:  [0, 1, 2]
x[-3:]: [0, 1, 2]
x[:-3]: [3, 4, 5]
x[:]:   [0, 1, 2, 3, 4, 5]
x+x:    [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5]
x*2:    [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5]
2*x:    [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5]
x:      [1, 'A']
x:      [1, [2, 'Hello Wrold'], 'X', 3]
(1,)
(1, 2, 3)
(1, 'A', 2, 'B')
(1, 'A', ('x', 'y', 3), 4, 'Hello World')
(1, 'A', [1, 2, 3], 4, 'Hello World')
range(1,10):    [1, 2, 3, 4, 5, 6, 7, 8, 9]
range(1,10,3):  [1, 4, 7]
xrange(1,10):   xrange(1, 10)
xrange(1,10,3): xrange(1, 10, 3)
x:      {2: 'B', 1: 'A'}
x[1]:   A
x:      {2: [1, 2, 3], 'A': 'This is a string', 4: None, 'abc': ('a', 'b', 'c')}
x[A]:   This is a string
x[2]:   [1, 2, 3]
x["abc"]:       ('a', 'b', 'c')
x[4]:   None

语句语法:

从以上各节可以知道,Jython 的语法很简单。它与英语非常类似,而不像 C 和 Java 语言。具体来说,每个源代码行(通常)是单个语句。除了 expression 和 assignment 语句外,每个语句都由关键字名称(如 if 或 for)引入。在任意两个语句之间都可以加空行或备注。
不需要在每行的结尾加分号,但如果愿意,也可以加。如果希望每行包含多条语句,则需要用分号来分隔语句。
如有必要,语句可以延续到超过一行。将一个反斜杠字符放在一行的末尾可以延续到任意行,如下所示:

x = "A looooooooooooooooooooooooooooooooong string " + \
     "another looooooooooooooooooooooooooooooooong string"

判断和循环例子:

pass;

a,b,c = 1,2,3;
print a,b,c;

a = b = c = 100;
print a,b,c;

if not None:
	print "None is False";
	
if not 0:
	print "0 is False";

if -1:
	print "-1 is True";


if x==0:
	print "block if";
elif x==1:
	print "block elif1";
elif x==2:
	print "block elif2";
else:
	print "block else";


x = 3;
while x>0:
	x-=1;
	print x;

for v in (1,2,3):
	print v;

for k,v in {1:"A",2:"B",3:"C"}.items():
	print k,v;

输出:

1 2 3
100 100 100
None is False
0 is False
-1 is True
block elif1
2
1
0
1
2
3
3 C
2 B
1 A

动态代码求值:

Jython 与一般的语言不同,它有能力动态创建代码,然后执行。例如,在计算器应用程序中,用户可以用文本形式输入表达式,Jython 可以直接执行该表达式(假设它符合 Jython 源代码规则)。
要较好地了解 Jython 如何对动态代码解释/求值,请考虑下列代码:

v1 = 100; v2 = 200
l1 = [1, 2, v1, v2]
d1 = {"simple":123, "complex":(v1, v2, l1)}
expr = raw_input("Enter an expression:")
print eval(expr)    # evaluate and print the expression

 Eval、exec 和 execfile:

eval 函数用于执行返回值的表达式。exec 语句用于对不返回值的代码块(一条或多条语句)进行求值,它将文件、字符串(常从文件中读取)或函数作为自己的源操作数。execfile 函数执行来自文件的代码块,它实际上是运行一个子程序。
exec 语句采用下列形式:

exec source {in globals {, locals}}

execfile 和 eval 函数采用下列形式:

execfile(filename, {globals {, locals}})
eval(expression, {globals {, locals}})

所有三种形式都有选择地采用定义全局名称空间和局部名称空间的两个字典。如果省略了这些字典,则使用当前的局部名称空间(由 locals 函数提供)和当前的全局名称空间(由 globals 函数提供)。
例如,如果字典 gd = {“one”:1, “two”:2} 和 ld = {“x”:100, “y”:-1} 用作名称空间,则: print eval(“one + two * 2 + x + y”, gd, ld)
输入结果为:104。

关于模块和导入:

Jython 将程序分成不同的文件,称为模块。通过将模块导入代码中,模块就能被重用。Jython 提供了许多可以重用的模块(请参见附录 F:Jython 库汇总)。Jython 还允许重用任何 Java 类和 API。

模块和包

模块是可执行的 Jython 文件,其中包含变量、函数和类等的定义。模块被导入(执行和绑定)到其他程序/脚本或模块中。当导入程序或模块需要使用导入模块中的一些或所有定义时,就有必要导入模块。
Jython 包是概念上有层次结构的模块的集合。它们以目录的方式实现的,这些目录包含一个或多个模块和特殊文件 __init__.py,该文件在包中第一个模块执行之前执行。
模块和包允许重用扩展标准 Jython 和 Java 库。您还可以创建在自己的 Jython 应用程序中重用的模块和包。有关可用的 Jython 模块的更多信息,请参见 附录 F:Jython 库汇总 。有关可用的 Java 库的更多信息,请访问 Sun Microsystems 的 Java 技术主页(在 参考资料 中)。

import 语句

import 语句执行另一个文件,并将绑定在它中的某些或所有名称都添加到当前名称空间中(请参见 可见性和作用域)。在导入文件中,当前名称空间一般是全局名称空间。该模块中的所有语句(包括赋值语句)都被执行。import 语句有几种形式:

import module {as alias}
   -- or --
from module import name {as alias}
   -- or --
from module import *

 module 值将 Jython (.py) 文件或加点的路径命名为 Jython 包。name 值从模块中选择特定的名称。模块名称是区分大小写的。这些参数可以重复。可选择的 alias 值允许对导入的对象重新命名。

导入的例子:

下面是一些 import 语句的例子:

例子 注释
import sys 导入 sys 模块。sys 中的所有名称都可以通过前缀 sys 来引用。
from sys import exc_info 从 sys 模块导入 exc_info 函数。不需要前缀。
from sys import * 导入 sys 模块中的所有名称和函数。不需要前缀。
from sys import exc_info as einfo 从 sys 模块中导入 exc_info 函数并将其命名为 einfo。不需要前缀。
from string import uppercase as uc, lowercase as lc 从模块 string 中导入 uppercase 和 lowercase 函数。不需要前缀。
import sys, string 导入模块 sys and string
import com.ibm.tools.compiler as compiler 从 com.ibm.tools 包中导入 compiler,并取一个短名称 compiler。

导入模块和包:

要导入模块或包,Jython 必须能找到相关的源文件 (.py)。Jython 使用 Jython 注册表中的 python.path(与 Java 语言的 CLASSPATH 非常类似)和 python.prepath 变量来搜索这些文件。您可以使用任何文本编辑器来添加或更新 Jython 主目录(通常为 c:\jython-2.1)中的 registry 文件。有关更多信息,请参见 Jython 注册表(在 参考资料 中)或 registry 文件本身。
默认情况下,Jython 将搜索包含执行源文件的目录;因此,可以找到与正在导入的 Jython 程序位于同一个目录中的模块。当前目录通常也在该路径中。只要输入下例命令就可查出当前搜索路径:

import sys
print sys.path

要找到 Java 类文件,Jython 既搜索 Java CLASSPATH,也搜索 sys.path 值。

import 是可执行的

与 Java 语言不同,import 语句在 Jython 中是可执行的,但它不是编译器指令。因此,不需要在模块开始就执行导入;而仅在使用已导入符号(imported symbols)之前执行。实际上,导入可以有条件地完成,如下例所示:

# lots of other stuff
   :
if __name__ == "__main__":
     :
     from sys import exit
     exit(0)

 导入也可以被撤销,如下所示:

import sys
   :
# lots of other stuff
   :
del sys

 子集导入:

当导入模块时,已赋值的所有值或在模块中创建的函数通常都可以由模块导入程序(importer)引用。您可以通过改变模块中的代码来防止出现此类情况。以下划线 (_) 作为名称的开头或在模块的开始定义一个特殊的变量 __all__,这样可以只列出要导入的变量或函数的名称。例如,下列 __all__ 定义:
__all__ = ["getline","clearcache","checkcache"]

只导入名称 getline、clearcache 和 checkcache。
在模块目录级别可以采用类似的策略。在名为 __init__.py 的文件中定义变量 __all__,指示解释器要从模块中导入哪些模块(如果在导入语句中使用了通配符 (*))。例如,如果 __all__ = [‘mod1’, ‘mod3’, ‘globals’] 行位于名为 modules 目录下叫做__init__.py 的文件中,它将导致语句 from modules import * 从 modules 目录导入模块 mod1、mod3 和 globals。

运行本机应用程序: 

通过 os.system 函数,Jython 还可以运行任何在当前主机 PATH 中找到的外部程序,如主机操作系统应用程序。例如,要编译 Java 程序,可以使用

import os
import sys

cmd = "javac %(name)s.java 1>%(name)s.out 2>%(name)s.err" % \
                 {'name': sys.argv[1]})
rc = os.system(cmd)
if rc == 0:
     print "Successful"
else:
     print "Failed: return code=%i..." % rc
     # read and process the .err file...

Jython 异常: 

关于异常:

不论程序员是如何仔细设计和测试其代码,都可能发生意外错误,即异常。Jython 为恢复这些错误提供了优异的支持。
异常通常是 Jython 类型 exceptions.Exception 或 Java 类 java.lang.Exception 的子类。大多数 Jython 异常名称都以 “Error”(例如IOError 或 IndexError )或 “Warning”结尾。而 Java 异常以 “Error”(适用于关键异常)或 “Exception”(适用于一般可恢复异常)结尾。有关更多信息,请参见 Jython 异常层次结构 或 Python Library Reference(请参见 参考资料 获得一个链接)。

try-except-else 语句:

与 C++ 和 Java 语言类似,Jython 支持异常处理程序。这些处理程序由 try-except-else 语句定义,该语句具有如下所示的形式:

try: statement
except type, var: statement
  :
else: statement
-- or --

try:
    block
except type, var:
    block
  :
else:
    block

 可以用不同的 type 值重复 except 子句。如果这样,异常就不能有重叠的层次结构(即成为“兄弟”),或者必须按子异常到根异常的顺序进行排序。可选的 type 值是一个异常类型(或者是 exceptions.Exception 的子类,或者是 java.lang.Throwable 的子类)。如果缺少 type,则 except 子句捕获所有 Jython 和 Java 异常。可选的 var 值接收实际的异常对象。如果缺少 var,则异常对象是不能直接访问的。else 子句是可选的。只有在没有发生异常时才执行该语句。
如果在 try 子句中发生了异常,则该子句退出,进入第一个匹配的 except 子句(如果有)。如果匹配不到异常,则包含 try-except-else 的块退出且重新引发异常。
如果异常在 except 或 else 子句中引发,则该子句将退出,而新异常将在包含块中得到处理。

访问异常信息:

要访问有关异常的信息,可以使用上面描述的 except 子句中的值或 sys.exc_info 函数。例如,您可以使用下列函数,其中,type 是异常的类,value 是异常对象(使用 str(value) 来获得该消息),traceback 是执行跟踪,它是执行跟踪框架的链接表。

import sys
  :
try:
     :
except:
     type, value, traceback = sys.exc_info()

 try-finally 语句:

与 C++ 和 Java 语言一样,Jython 还支持结构 try-finally,采用该结构可以轻松地执行必需的清除活动,如关闭打开的文件、释放资源等。一旦进入 try 子句,finally 子句中的任何代码都要保证执行一次,即使通过返回语句(请参见 return 语句)或异常退出也是如此。try-finally 语句具有下列形式:

try: statement
finally: statement

  -- or --

try:
    block
finally:
    block

 raise 语句:

异常由被调用函数或内置服务生成。还可以使用 raise 语句生成异常。raise 语句具有下列形式:

raise exception

  -- or --

raise exception_class {, message}

  -- or --

raise

 

例子 注释
raise 重新引发当前的异常;在异常块中用于重新生成异常
raise IOError 创建和引发 IOError,没有消息
raise anIOError 重新引发现有的 IOError 对象
raise IOError, “End of File” 创建和引发 IOError,有解释性消息

from java import io 

raise io.IOException, “End of File”

创建和引发 Java 异常,有解释性消息

例子:

import sys;
try:
	x = 1/0;
except:
	print "traceback=",sys.exc_info();
else: 
	print x;
finally:
	print "finally block";

输出:

traceback= (, ZeroDivisionError('integer division or modulo by zero',),)
finally block

del 语句:

可变的序列(请参见 序列类型 )、映射(请参见 映射和字典)和类都支持 del 语句,该语句分别从集合或类中删除元素或属性。对序列而言,删除是按索引进行的;而对映射是按键值;对类是按属性名称。我们将在本教程的第 2 部分详细讨论 del 语句的类支持。
局部或全局变量可以被删除;这将从名称空间中删除变量(它不删除变量所引用的对象)。del 语句还支持切片表示法(slice notation)。
假设 “l” 是列表 [1,2,3,4,5],d 是字典 {1:”one”, 2:”two”, 3:”three”},而 x 某个类实例,下面是一些 del 语句的例子:

例子 注释
del l[0] 删除第一个元素
del l[1:3] 删除第二个到第三个元素
del l[::2] 删除偶数元素
del l[:] 删除所有元素
del d[1] 删除带有键的元素1
del x.attr1 删除属性attr1
var = [1,2,3] 

del var
从名称空间中删除变量var

def 语句:

在 Jython 中,函数通过 def 语句声明,该语句具有以下形式:

def name (  args  ): statement

  -- or --

def name ( args ):
    block

在给定的作用域(模块、函数或类)内,每个函数名都应是惟一的。函数名事实上是绑定到函数体的变量(类似于任何其他赋值)。实际上,可以定义多个变量来引用同一个函数。函数体可以是单个语句(通常是一个返回语句),也可以是语句块(这种情形更为常见)。

指定函数参数:

例子 注释
def x(a, b, c) 定义有三个必需位置参数的函数
def x(a, b, c=1) 定义有三个参数的函数,最后一个参数是可选的,其默认值为 1
def x(a=3, b=2, c=1) 定义有三个参数的函数,这三个参数都是可选的,都有默认值
def x(p1, p2, kw1=1, kw2=2) 定义一个有两个位置参数和两个关键字(可选)参数的函数。声明该函数时,所有可选参数(=值)参数必须在所有非可选参数之后。调用该函数时,关键字参数(如提供)可以在位置参数之后按名称以任何顺序指定
def x(p1, p2, *v) 定义一个具有两个必需位置参数和数量不确定的变量参数的函数。v 变量将是一个元组
def x(p1, p2, **kw) 定义一个具有两个必需位置参数和数量不确定的变量参数的函数。kw 变量是字典。
def x(p1, p2, *v, **kw) 定义一个具有两个必需位置参数和数量不确定的位置和关键字参数的函数。v 变量是元组。kw 变量是字典。

处理可变参数

如果参数接受可变对象(如列表和字典)的默认值,则最好采用下列形式:

def x(p1, p2, p3=None)
     if p3 is None: p3 = []
     :

例子:

#函数:
sumfun = lambda x,y:x+y;
print sumfun(1,2);

def fun1(a,b,c=1,*d,**e):
	print "a",a;
	print "b",b;
	print "c",c;
	print "d",d;
	print "e",e;

fun1("A","B");
fun1("A","B","C");
fun1("A","B","C","D","E","F");
fun1("A","B","C","D","E","F",aaa="M",xxx="N");

def fun2(a,b=None):
	print "a",a;
	print "b",b;

fun2(3,["A","B"]);
fun2(3,{"A":100,"B":200});

输出:

a A
b B
c 1
d ()
e {}
a A
b B
c C
d ()
e {}
a A
b B
c C
d ('D', 'E', 'F')
e {}
a A
b B
c C
d ('D', 'E', 'F')
e {'aaa': 'M', 'xxx': 'N'}
a 3
b ['A', 'B']
a 3
b {'B': 200, 'A': 100}

 global 语句:

有时,您可能希望在局部上下文中声明变量(即赋值),但在全局作用域中引用变量。为此,请在第一次使用变量前使用 global 语句。下面是一个例子:

x = 10; y = 20; z = 30  # three global variables

def f1(p, q, r):
     x = p      # local x, y & z variables
     y = q
     z = r

def f2(a, b, c):
     global x, y
     x = a      # global x & y variables
     y = b
     z = c      # local z variable

print x, y, z   # prints: 10, 20, 30

f1(1, 2, 3)
print x, y, z   # prints: 10, 20, 30

f2(-1, -2, -3)
print x, y, z   # prints: -1, -2, 30

 注意,只要全局变量没有被局部地重新绑定,那么在没有将其声明为全局的情况下,就可读取该变量。因此,只有在对全局变量赋值时才需要 global 语句。

嵌套函数

与许多其他语言(包括 Java 语言)不同,Jython 允许在其他函数内部定义函数。嵌套(或局部)函数有助于缩减函数的作用域。下面是一个例子:

def x(a, b, c):
     y = a * b

     def square(x):
         return x ** 2      # this x is different from function x

     y *= square(c)
     return x

 包含函数中的变量对嵌套函数是不可见的。如果嵌套函数必须使用这些值,则将这些值作为参数传递给嵌套函数。例如,下列函数

def calc(a, b, c):
     x = a * b * c

     def sum(data):
         # cannot access calc's namespace (x, a, b, c, or sum) here
         print locals()
         return data['a'] + data['b'] + data['c']

     x += sum(locals())
     return x

print calc(10,20,30)

 输出

{'data': {'x': 6000, 'c': 30, 'b': 20, 'sum': \
     <function sum at 32308441>, 'a': 10}}
6060

 使用嵌套函数还能方便地创建(预先配置)要作为结果返回的函数,如下所示:

def makeSq(n):
     def sq(x=n):  # n's value is saved as the parameter x value
         return x ** 2 
     return sq

上述函数可以像下面这样使用:

sq2 = makeSq(2)
print "2*2=%i" % sq2()     # prints: 2*2=4

sq10 = makeSq(10)
print "10*10=%i" % sq10()  # prints: 10*10=100

 

发表评论

1 × 1 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据