jython_Jython简介,第2部分:编程要点

关于本教程

本教程是关于什么的?

这是分两部分的教程的第二部分,旨在向您介绍Jython脚本语言。 Jython是已与Java平台无缝集成的Python实现。 Python是一种功能强大的面向对象的脚本语言,主要在UNIX环境中使用。

在本教程的第1部分中,您学习了Jython的基础知识,包括安装和设置,访问选项和文件编译,语法和数据类型,程序结构,过程语句和函数。 在第2部分中,我们将深入研究使用这种强大的脚本语言的一些更高级的方面,首先是对Jython的面向对象编程的深入介绍。 我们还将讨论任何语言对应用程序开发机制必不可少的主题,包括调试,字符串处理和文件I / O。

到您完成Jython的两部分介绍的下半部分时,您将能够在Jython中编写和实现完整的功能,类和程序。

我应该学习本教程吗?

本教程旨在逐步介绍Jython。 如果您尚未完成本教程的第1部分 ,则应在继续进行第2部分之前完成。如果不参考第1部分 ,那么概念性讨论和此处介绍的许多代码示例将很难遵循。

在本教程的后半部分,我们将介绍使用Jython编写脚本的以下方面:

  • 使用Jython进行面向对象的编程
  • 调试
  • Java支持
  • 字符串处理
  • 文件I / O
  • 在Jython中构建Swing GUI应用程序

要从讨论中受益,您应该熟悉至少一种过程编程语言和计算机编程的基本概念,包括命令行处理。 要充分利用Jython的功能,您还应该熟悉面向对象编程的基本概念。 为了完全理解本教程结尾处的GUI应用程序示例,您应该具有Swing GUI编程的先前经验,尽管您将能够从前面的讨论和示例中学到很多东西。 熟练掌握Java平台也将很有帮助,因为Jython运行在JVM上。 尽管这不是本教程的要求。

请注意,本教程是针对Windows系统的。 所有命令示例都将使用Windows语法。 在大多数情况下,相似的命令在UNIX系统上执行相同的功能,尽管不会演示这些命令。

工具,代码和安装要求

您必须在开发系统上安装Jython 2.1或更高版本才能完成本教程。 您的开发系统可以是与命令提示符结合使用的任何ASCII文本编辑器(例如Windows记事本)。 本教程包括有关在系统上获取和安装Jython的详细说明。

要使用Jython,您还必须在系统上安装Java运行时环境(JRE)。 建议您使用最新的JRE(在撰写本文时为1.4.2),但是Java 1.2或更高版本的任何版本都可以正常工作。 如果要在浏览器中使用Jython(即作为小程序),则必须至少对浏览器有JRE 1.1可用。 请参阅“ 相关主题”部分以下载最新版本的JDK。

本教程中的所有代码示例均已在Windows 2000上的Sun Java 1.4.1 JRE上运行的Jython上进行了测试。示例在其他操作系统上的任何类似配置上均应保持不变。

本教程包括一组附录,详细介绍了您将用来了解Jython的所有代码示例。 所有代码示例均已在Windows 2000的Sun Java 1.4.1 JRE上运行的Jython上进行了测试。这些示例在其他操作系统上的任何类似配置上均应保持不变。

Jython中的面向对象编程

概念概述

面向对象编程(OOP)代表了软件编程技术的最新发展。 OOP基于在程序中创建目标问题的模型 (或仿真)的概念。 正确使用OOP技术可减少编程错误,加快软件开发速度,并促进现有代码的重用。 Jython完全支持OOP的概念和实践。

在以下各节中,我将介绍OOP并描述如何在Jython中实现。 在下一节中,我将讨论Jython中面向对象编程的一些更高级的功能。

Jython中的对象

Jython是一种面向对象的语言,完全支持面向对象的编程。 Jython定义的对象具有以下功能:

  • 身份 :每个对象都必须是不同的,并且必须是可测试的。 为此,Jython支持isis not测试。
  • 状态 :每个对象都必须能够存储状态。 Jython为此提供了属性 (又名字段或实例变量 )。
  • 行为 :每个对象必须能够操纵其状态。 Jython提供了用于此目的的方法 。

请注意, id(object)内置函数返回唯一的整数标识值。 因此,表达式x is y等于id(x) == id(y)

Jython中的OOP支持

在对面向对象编程的支持中,Jython包括以下功能:

  • 基于类的对象创建 :Jython 类是用于创建对象的模板。 对象是具有相关行为的数据结构。
  • 具有多态性的继承 :Jython支持单 继承和多继承 。 所有Jython实例方法都是多态的 (或virtual ),并且可以被子类覆盖。
  • 隐藏数据的封装 :Jython允许(但不要求)隐藏属性,因此仅允许通过类的方法在类外部进行访问。 类实现函数(称为方法)来修改数据。

定义班级

定义类非常类似于定义模块,因为可以定义变量和函数。 与Java语言不同,Jython允许每个源文件(或模块)定义任意数量的公共类。 因此,Jython中的模块非常类似于Java语言中的软件包。

我们使用class语句在Jython中定义类。 class语句具有以下形式:

class name ( superclasses ):  statement

  -- or --

class name ( superclasses ): 
    assignment
     :

    function
     :

定义类时,可以选择提供零个或多个赋值语句。 这些创建由类的所有实例共享的类属性。 您还可以提供零个或多个函数定义。 这些创建方法。 超类列表是可选的。 我们将在本教程的稍后部分讨论超类。

类名在相同范围(模块,函数或类)中应该唯一。 类名实际上是绑定到类主体的变量(类似于任何其他分配)。 实际上,您可以定义多个变量来引用同一类。

创建一个类实例

类用于保存类(或共享)属性或创建类实例。 要创建类的实例,您可以像调用一个函数一样调用该类。 无需像C ++或Java语言那样使用新的运算符。 例如,与类

class MyClass:
    pass

以下语句创建一个实例:

x = MyClass()

向类实例添加属性

在Jython中(不同于Java语言),客户端可以将字段 (也称为attribute )添加到实例。 仅一个实例被更改。 要将字段添加到实例( x ),只需在该实例上设置新值,如下所示:

x.attr1 = 1
x.attr2 = 2
  :
x.attrN = n

定义类属性和方法

绑定到类中的任何变量都是类属性 (或变量)。 在类中定义的任何函数都是方法 。 方法接收该类的实例(通常称为self )作为第一个(可能是唯一的)参数。 例如,要定义一些类属性和方法,可以输入:

class MyClass:
    attr1 = 10        # class attributes
    attr2 = "hello"

    def method1(self):
        print MyClass.attr1   # reference the class attribute

    def method2(self, p1, p2):
        print MyClass.attr2   # reference the class attribute

    def method3(self, text):
        self.text = text    # instance attribute
        print text, self.text    # print my argument and my attribute

    method4 = method3       # make an alias for method3

请注意,在类内部,应使用类名称(例如MyClass.attr1 )限定对类属性的所有引用,并使用self变量(例如self.text )对所有实例属性的引用进行限定。 在类之外,应该使用类名(例如MyClass.attr1 )或实例(例如x.attr1 )来限定对类属性的所有引用,并使用实例(例如x.text )来x.attr1对实例属性的所有引用x.text ,其中x是该类的实例)。

隐藏变量

为了实现数据隐藏,通常需要创建“私有”变量,该变量只能由类本身访问。 Jython提供了一种命名约定,使在类之外访问属性和方法变得困难。 如果您声明以下形式的名称: __xxx或__xxx_yyy (这是两个下划线),则Jython解析器将自动修改(即,将类名添加到)声明的名称,实际上创建了隐藏变量。 例如:

class MyClass:
    __attr = 10               # private class attribute

    def method1(self):
        pass        

    def method2(self, p1, p2):
        pass       

    def __privateMethod(self, text):
        self.__text = text    # private attribute

请注意,与C ++和Java语言不同,对实例变量的所有引用都必须使用self限定; 有没有隐含使用this

初始化方法

__init__方法充当实例构造函数的角色。 每当创建实例时都会调用它。 应该为所有类定义此方法。 方法__init__可以接受参数。 在Jython中,与C ++或Java语言不同,所有实例变量(也称为属性或字段)都是通过赋值动态创建的。 它们应该在__init__内定义(即分配给)。 这样可以确保为后续使用方法定义它们。 一些示例如下:

class Class1:
    def __init__ (self):             # no arguments
        self.data = []               # set implicit data

class Class2:
    def __init__ (self, v1, v2):     # 2 required arguments
        self.v1 = v1                 # set data from parameters
        self.v2 = v2

class Class3:
    def __init__ (self, values=None): # 1 optional argument
        if values is None: values = []
        self.values = values          # set data from parameter

del方法

如果您在__init__方法(或任何其他方法)中分配了任何资源,则需要确保在释放对象之前释放这些资源。 最好的方法是使用__del__方法。 在垃圾回收器释放对象之前,将调用__del__方法。 您还应该提供可以直接调用的清理方法(通常称为closedestroydispose )。 这是一个例子:

class Class:
    def __init__ (self, db):    
        self.connection = db.getConnection()    # establish a connection
        self.connection.open()

    def __del__ (self):                         # cleanup at death
        self.close()

    def close(self):                            # cleanup
        if not self.connection is None and self.connection.isOpen():
            self.connection.close()             # release connection
        self.connection = None

使用类作为值

也可以将类分配给变量(包括函数参数)。 从以下通用类实例工厂可以看出,这使得基于类编写动态代码变得非常容易:

def instanceMaker(xclass, *args):
    return apply(xclass, args)

 :

x = instanceMaker(MyClass)   # same as: x = MyClass()

遗产

从类继承的能力是面向对象编程的基础。 Jython支持单继承和多继承。 单一继承意味着只能有一个超类。 多重继承意味着可以有多个超类。

继承是通过对其他类进行子类化来实现的。 这些类可以是其他Jython类或Java类。 任何数量的纯Jython类或Java接口都可以是超类,但是只能(直接或间接)继承一个Java类。 您不需要提供超类。

超类中的任何属性或方法也都在任何子类中,并且可由类本身或任何客户端使用(假定它是公开可见的)。 只要可以使用超类的实例,就可以使用子类的任何实例-这是多态的一个示例。 这些功能使重用,快速开发和易于扩展成为可能。

以下是继承的一些示例:

class Class1: pass                # no inheritance

class Class2: pass

class Class3(Class1): pass        # single inheritance

class Class4(Class3,Class2): pass # multiple inheritance

from java import awt
from java import io         

# inherit a Java class and interface and a Jython class
class MyPanel(awt.Panel, io.Serializable, Class2): 
    :

具有继承的init方法

子类的__init__方法必须调用为其父类定义的任何__init__方法。 这不是自动的。 下面的两个示例演示了如何将__init__方法与继承一起使用。

class Class1(SuperClass):
    def __init__ (self):               # no arguments
        SuperClass.__init__(self)      # init my super-class
        self.data = []                 # set implicit data

class Class2(SuperClass):
    def __init__ (self, v1, v2):       # 2 required arguments
        SuperClass.__init__(self, v1)  # init my super-class with v1
        self.v2 = v2

以下是一些使用多重继承进行初始化的示例:

class Class1(Super1, Super2):
    def __init__ (self):               # no arguments
        Super1.__init__(self)          # init each super-class
        Super2.__init__(self)
        self.data = []                 # set implicit data

class Class2(Super1, Super2):
    def __init__ (self, v1, v2, v3):   # 3 required arguments
        # note you may do work before calling the super __init__ methods
        self.v3 = v3                   # set data from parameter
        Super1.__init__(self, v1)      # init each super-class
        Super2.__init__(self, v2)

调用超类方法

您可以通过使用类名限定任何超类方法来调用它,如下所示:

class Class1:
    def method1 (self):             
        :

class Class2(Class1):
    def method1 (self):         # override method1
        :
        Class1.method1(self)    # call my super-class method
        :

    def method2 (self):             
        :

class Class3(Class2):
    def method1 (self):         # override method1
        :
        Class2.method1(self)    # call my super-class method
        :

    def method3 (self):             
        :

请注意,辅助方法定义(在Class2Class3 )将覆盖超类定义。 不需要子类方法调用其超类方法; 但是,如果没有,则必须完全替换超类方法的功能。

调用方式

调用方法有两种语法(假设您有一个由变量mci引用的MyClass实例):

  • mci.someMethod(...)
  • MyClass.someMethod(mci, ...)

第一种形式通常用于类客户端编码中,而第二种形式通常用于子类中以调用超类方法。

先进的面向对象编程

从理论到实践

在本节中,我们将从Jython中的面向对象编程的概念概述转到更高级的讨论,其中包含诸如运算符重载,特殊属性和自省之类的主题。

特殊属性

Jython类为几种特殊属性提供支持。 最重要的信息如下所示:

名称 角色 注释)
__dict__ 对象的可写属性 可用于内省对象的属性
__class__ 对象的类别 访问对象的类(类似于Java编码中的x.getClass()
__bases__ 对象的直接超类的元组 可用于内省对象的超类

更改现有实例的类

与大多数其他语言不同,在Jython中,您可以更改现有实例的类。 这样做会将您可以在实例上使用的方法更改为新类的方法,但不会更改其任何现有字段。 例如,要更改实例的类,请将新类分配给__class__特殊属性(请参见特殊属性 ),如下所示:

x = SomeClass()               
print isinstance(x, SomeClass)       # prints: 1 (true)
print isinstance(x, SomeOtherClass)  # prints: 0 (false)
 :
# change the class (that is, the type) of the instance here
x.__class__ = SomeOtherClass  
print isinstance(x, SomeClass)       # prints: 0 (false)
print isinstance(x, SomeOtherClass)  # prints: 1 (true)

y = SomeOtherClass()               
print x.__class__ == y.__class__     # prints: 1 (true)

进行此更改之后, x实例将支持SomeOtherClass的方法,而不是以前的SomeClass 更改对象的类时,请注意实例具有新类的正确属性。

自省属性示例

这是一个使用特殊属性的实际示例(请参阅特殊属性 )。 模块printclass.py可以内省类和实例以显示其属性和方法。 稍后再讨论内省,或者您可以查看内省 。 您还可以查看String操作和函数以及附录K:内置函数,以了解有关下面使用的函数的更多信息。 现在,仅关注callable函数, vars函数(隐式使用__dict__属性)和__bases__属性的使用。

__any__ = ['getMembers', 'printObject']

def addMember (list, item):
    if not item in list:
        list.append(item)

def getMembers (obj, memtype="attrs"):
    """ Get all the members (of memtype) of the object. """
    members = []
    for name, value in vars(obj).items():
        try:
            item = obj.__name__, name, value
        except:
            item = "", name, value
        if   memtype.lower().startswith("attr"):
            if not callable(value):
                addMember(members, item)
        elif memtype.lower().startswith("meth"):
            if callable(value):
               addMember(members, item)
        elif memtype.lower() == "all":
            addMember(members, item)
    try:
        for base in obj.__bases__:
            members.extend(getMembers(base, memtype))
    except:
        pass
    return members

import sys

def printObject (obj, stream=sys.stdout):
    """ Print all the members of the object. """
    members = getMembers(obj, "attrs")
    members.sort() 
    print >>stream, "Attributes:"
    for objname, memname, value in members:
        print >>stream, "  %s.%s" % (objname, memname)

    members = getMembers(obj, "methods")
    members.sort() 
    print >>stream, "Methods:"
    for objname, memname, value in members:
        print >>stream, "  %s.%s" % (objname, memname)

自省属性示例测试用例

下面的代码使用上一部分中的函数来内省UserList类。 有关UserList类的定义,请参见运算符重载 。

if __name__ == "__main__":

    from UserList import UserList
    
    class MyClass(UserList):
        def __init__ (self, x, y):
            UserList.__init__(self)
            self.__x = x
            self.__y = y
    
        def method1 (self):
            return self.x + self.y
    
        def method2 (self, x, y):
            return  self.x + self.y + x + y

    print "For class:", `MyClass`
    printObject(MyClass)
    print 

    aMyClass = MyClass(1, 2)
    aMyClass.extend([1,2,3,4])
    print "For instance:", `aMyClass`
    printObject(aMyClass)

获取成员的输出

以下输出(重新格式化为多列以节省空间)是上述模块中运行主代码的结果。 请注意,私有字段和方法(请参阅隐藏变量 )具有错误的名称。

For class: 
Attributes:            Methods:                     
  MyClass.__doc__        MyClass.__init__         UserList.__len__            
  MyClass.__module__     MyClass.method1          UserList.__lt__             
  UserList.__doc__       MyClass.method2          UserList.__mul__            
  UserList.__module__    UserList._UserList__cast UserList.__ne__             
                         UserList.__add__         UserList.__radd__           
                         UserList.__cmp__         UserList.__repr__           
                         UserList.__contains__    UserList.__rmul__           
                         UserList.__delitem__     UserList.__setitem__        
                         UserList.__delslice__    UserList.__setslice__       
                         UserList.__eq__          UserList.append             
                         UserList.__ge__          UserList.count              
                         UserList.__getitem__     UserList.extend             
                         UserList.__getslice__    UserList.index              
                         UserList.__gt__          UserList.insert             
                         UserList.__iadd__        UserList.pop                
                         UserList.__imul__        UserList.remove             
                         UserList.__init__        UserList.reverse            
                         UserList.__le__          UserList.sort               

For instance: [1, 2, 3, 4]
Attributes:                    
  ._MyClass__x
  ._MyClass__y
  .data

Methods:

请注意,方法和类属性与类一起驻留,实例属性与实例一起驻留。 但是,所有类的方法都可以应用于每个实例。

内省

您通常需要在运行时确定对象的特征。 我们称这是对对象的自省 。 Java平台通过java.lang.Class类和java.lang.reflect包中的类提供自省服务。 尽管功能强大,但这些API还是有些难以使用。 您可能已经怀疑过,Jython提供了一种更简单的内省方法。

在Jython中,我们可以使用dirvars函数检查任何对象的绑定,例如模块,函数,类,序列,映射等。 为了更好地了解其工作原理,请考虑以下示例。 输出已插入到以“ ...”为前缀的print语句之后(并重新格式化),以便于阅读。 dir函数仅返回绑定名称,而vars函数返回名称和值; 因此,当两个函数返回相同的名称时,我们只需要使用vars函数,如下所示:

#-- empty start --
print "vars:", vars()
...vars: {'__doc__': None, '__name__': '__main__'}

x = 1
y = 2
z = 3
l = [x, y, z]
d = {x:"xxxx", y:"yyyy", z:"zzzz"}

#-- locals variables --
print x, y, z, l, d
...1 2 3 [1, 2, 3] {3: 'zzzz', 2: 'yyyy', 1: 'xxxx'}

#-- plus locals variables --
print "vars:", vars()
...vars: {'__name__': '__main__', 'x': 1, \
... 'd': {3: 'zzzz', 2: 'yyyy', 1: 'xxxx'}, '__doc__': None, \
... 'y': 2, 'l': [1, 2, 3], 'z': 3}

import sys

#-- plus import --
print "vars:", vars()
...vars: {'__name__': '__main__', 'z': 3, 'l': [1, 2, 3], \
... '__doc__': None, 'y': 2, 'x': 1, 'sys': sys module, \
... 'd': {3: 'zzzz', 2: 'yyyy', 1: 'xxxx'}}

#-- sys import --
print "vars sys:", vars(sys)  
...vars sys: {'classLoader': \
...     , 
...     ... many values removed ...,
... 'warnoptions': }

del x, y, z

#-- post delete --
print "vars:", vars()
...vars: {'__name__': '__main__', 'l': [1, 2, 3], '__doc__': None, \
... 'sys': sys module, 'd': {3: 'zzzz', 2: 'yyyy', 1: 'xxxx'}}

def func (x, y):
    return x, y

class MyClass ():
    def __init__ (self, x, y):
        self.__x = x
        self.__y = y

    def method1 (self):
        return self.x + self.y

    def method2 (self, x, y):
        return  self.x + self.y + x + y

#-- plus function and class --
print "vars:", vars()
....vars: {'func': , '__name__': '__main__', \
...  'l': [1, 2, 3], '__doc__': None, \
.... 'MyClass': , \
...  'sys': sys module, 'd': {3: 'zzzz', 2: 'yyyy', 1: 'xxxx'}}

#-- function --
print "dir: ", dir(func)     # **** dir and vars different here ****
print "vars:", vars(func)
...dir:  ['__dict__', '__doc__', '__name__', 'func_closure', \
... 'func_code', 'func_defaults', 'func_doc', 'func_globals', 'func_name']
...vars: None

#-- class --
print "vars:", vars(MyClass)
...vars: {'__doc__': None, '__init__': , \
... 'method2': , '__module__': '__main__', \
... 'method1': }

myclass = MyClass(1, 2)

#-- instance --
print "myclass:", myclass
print "vars:", vars(myclass)
...myclass: <__main__.MyClass instance at 19014134>
...vars: {'_MyClass__y': 2, '_MyClass__x': 1}

请注意, dir(x)通常等效于x.__dict__.keys()vars(x)通常等效于x.__dict__

自省的附加功能

特殊属性中描述的属性允许对类进行其他自省。 特别是,您可以使用__dict__属性来确定类中的方法和实例中的字段。

除了dirvars ,Jython还提供了更多用于自省类和实例的函数,如下所示:

功能 注释)
hasattr(obj, name) 测试以查看命名属性是否存在
getattr(obj, name {, default}) 获取命名属性(如果存在); 否则,返回默认值(如果没有提供默认值,则引发异常)
setattr(obj, name, value) 设置命名属性的值
delattr(obj, name) 删除命名属性

请参阅附录K:内置功能以了解有关这些功能的更多信息。

抽象类

抽象类是其中某些或所有方法均缺失或定义不完整的类。 必须创建一个子类来提供或完成这些方法定义。 具体的类不是抽象的(也就是说,所有方法都是完整的)。 到目前为止,我们仅与具体的类一起工作。 创建抽象类以促进重用。 它们提供了设计的部分实现,您可以通过将其子类化来完成或扩展设计。

为了更好地了解其工作原理,我们将创建一个简单的抽象命令框架,该框架支持命令doundoredo操作。 命令在(子)类中定义,可以通过创建新的do_...undo_...方法轻松添加。 如前几节所述,我们通过自省访问了这些方法。

抽象命令框架

这是示例抽象命令框架:

class CommandProcessor:   # an abstract class
    """ Process Commands. """

    def __init__ (self):
        self.__history = []
        self.__redo = []

    def execute (self, cmdName, *args):
        """ Do some command """
        self.__history.append( (cmdName, args) )
        processor = getattr(self, "do_%s" % cmdName, None)
        if processor:
            return processor(*args)
        else:
            raise NameError, "cannot find do_%s" % cmdName

    def undo (self, count=1):
        """ Undo some (or all) commands in LIFO order """
        self.__redo = []
        while count > 0 and len(self.__history) > 0:
            cmdName, args = self.__history.pop()
            count -= 1
            processor = getattr(self, "undo_%s" % cmdName, None)
            if processor:
                self.__redo.append( (cmdName, args) )
                processor(*args)
            else:
                raise NameError, "cannot find undo_%s" % cmdName

    def redo (self, count=1):
        """ Redo some (or all) undone commands """
        while count > 0 and len(self.__redo) > 0:
            cmdName, args = self.__redo.pop()
            count -= 1
            processor = getattr(self, "do_%s" % cmdName, None)
            if processor:
                processor(*args)
            else:
                raise NameError, "cannot find do_%s" % cmdName

注意:此示例基于Samuele Pedroni和Noel Rappin的Jython Essentials中的代码( 有关更多信息,请参见参考资料)。

示例框架的测试用例

这是示例抽象命令框架的测试用例:

class MyProcessor (CommandProcessor):  # a concrete subclass
    def __init__ (self):
        CommandProcessor.__init__(self)

    def do_Cmd1 (self, args):
        print "Do Command 1:", args

    def do_Cmd2 (self, args):
        print "Do Command 2:", args

    def do_Cmd3 (self, args):
        print "Do Command 3:", args

    def undo_Cmd1 (self, args):
        print "Undo Command 1:", args

    def undo_Cmd2 (self, args):
        print "Undo Command 2:", args

    def undo_Cmd3 (self, args):
        print "Undo Command 3:", args

mp = MyProcessor()

print "execute:" ; mp.execute("Cmd1", None)
print "execute:" ; mp.execute("Cmd2", (1,2,3))
print "execute:" ; mp.execute("Cmd3", "Hello")
print "undo:   " ; mp.undo(2)
print "redo:   " ; mp.redo(2)

print "execute:", ;mp.execute("BadCmd", "Hello")

具有给定测试用例的框架将产生以下输出:

execute:
Do Command 1: None
execute:
Do Command 2: (1, 2, 3)
execute:
Do Command 3: Hello
undo:   
Undo Command 3: Hello
Undo Command 2: (1, 2, 3)
redo:   
Do Command 2: (1, 2, 3)
Do Command 3: Hello
execute:
Traceback (innermost last):
  File "cmdproc.py", line 63, in ?
  File "cmdproc.py", line 15, in execute
NameError: cannot find do_BadCmd

运算符重载

与C ++一样,但与Java语言不同,Jython允许许多标准语言运算符被类重载。 这意味着类可以为语言运算符定义特定的含义。 Jython还允许类模拟内置类型,例如数字,序列和映射。 要了解有关仿真的更多信息,请参见附录B:常见的重载运算符和方法 。

在下面的示例中,我们将使用标准的Jython UserList类定义来展示实际中的运算符重载的示例。 UserList是包装列表并像列表一样工作的类。 它的大部分功能都被委托 (传递给)了它所包含的列表,称为data 在更现实的示例中,将实现这些重载功能以访问某些其他存储,例如磁盘文件或数据库。

class UserList:
    def __init__(self, initlist=None):
        self.data = []
        if initlist is not None:
            if   type(initlist) == type(self.data):
                self.data[:] = initlist
            elif isinstance(initlist, UserList):
                self.data[:] = initlist.data[:]
            else:
                self.data = list(initlist)

    def __cast(self, other):
        if isinstance(other, UserList): return other.data
        else:                           return other

    #  `self`, repr(self)
    def __repr__(self): return repr(self.data)

    #  self < other
    def __lt__(self, other): return self.data <  self.__cast(other)

    #  self <= other
    def __le__(self, other): return self.data <= self.__cast(other)

    #  self == other
    def __eq__(self, other): return self.data == self.__cast(other)

    #  self != other, self <> other
    def __ne__(self, other): return self.data != self.__cast(other)

    #  self > other
    def __gt__(self, other): return self.data >  self.__cast(other)

    #  self >= other
    def __ge__(self, other): return self.data >= self.__cast(other)

    #  cmp(self, other)
    def __cmp__(self, other):
        raise RuntimeError, "UserList.__cmp__() is obsolete"

    #  item in self
    def __contains__(self, item): return item in self.data

    #  len(self)
    def __len__(self): return len(self.data)

    #  self[i]
    def __getitem__(self, i): return self.data[i]

    #  self[i] = item
    def __setitem__(self, i, item): self.data[i] = item

    #  del self[i]
    def __delitem__(self, i): del self.data[i]

    #  self[i:j]
    def __getslice__(self, i, j):
        i = max(i, 0); j = max(j, 0)
        return self.__class__(self.data[i:j])

    #  self[i:j] = other
    def __setslice__(self, i, j, other):
        i = max(i, 0); j = max(j, 0)
        if   isinstance(other, UserList):
            self.data[i:j] = other.data
        elif isinstance(other, type(self.data)):
            self.data[i:j] = other
        else:
            self.data[i:j] = list(other)

    #  del self[i:j]
    def __delslice__(self, i, j):
        i = max(i, 0); j = max(j, 0)
        del self.data[i:j]

    #  self + other   (join)
    def __add__(self, other):
        if   isinstance(other, UserList):
            return self.__class__(self.data + other.data)
        elif isinstance(other, type(self.data)):
            return self.__class__(self.data + other)
        else:
            return self.__class__(self.data + list(other))

    #  other + self   (join)
    def __radd__(self, other):
        if   isinstance(other, UserList):
            return self.__class__(other.data + self.data)
        elif isinstance(other, type(self.data)):
            return self.__class__(other + self.data)
        else:
            return self.__class__(list(other) + self.data)

    #  self += other  (join)
    def __iadd__(self, other):
        if   isinstance(other, UserList):
            self.data += other.data
        elif isinstance(other, type(self.data)):
            self.data += other
        else:
            self.data += list(other)
        return self

    #  self * other   (repeat)
    def __mul__(self, n):
        return self.__class__(self.data*n)
    __rmul__ = __mul__

    #  self *= other  (repeat)
    def __imul__(self, n):
        self.data *= n
        return self

    # implement "List" functions below:

    def append(self, item): self.data.append(item)

    def insert(self, i, item): self.data.insert(i, item)

    def pop(self, i=-1): return self.data.pop(i)

    def remove(self, item): self.data.remove(item)

    def count(self, item): return self.data.count(item)

    def index(self, item): return self.data.index(item)

    def reverse(self): self.data.reverse()

    def sort(self, *args): apply(self.data.sort, args)

    def extend(self, other):
        if isinstance(other, UserList):
            self.data.extend(other.data)
        else:
            self.data.extend(other)

嵌套类

像函数一样,类可以嵌套。 Jython中的嵌套类的工作方式类似于Java语言中的静态内部类。 这是一个例子:

class MyDataWrapper:
    class Data: pass    # inner data structure class

    def __init__ (self):
        self.data = Data()

    def set (self, name, value):
        setattr(self.data, name, value)

    def get (self, name, default=None):
        return getattr(self.data, name, default)

调试Jython

使用打印语句进行调试

与任何编程语言一样,Jython支持使用print语句进行调试。 要实现此调试解决方案,我们只需在程序中添加一条print语句,运行该程序,然后检查生成的输出以查找错误的线索。 尽管非常基础,但在许多情况下,此调试解决方案还是完全令人满意的。

这是用于调试的示例print语句。

:
def myFunc(x):
    print "x at entry:", x
      :
    print "x at exit:", x
    return x
:

z = myFunc(20)

Jython调试器

对于print statement解决方案不足以满足调试需求的时代,Jython提供了一个简单的命令行调试器,类似于Java平台的jdb调试器。 Jython调试器完全用Jython编写,因此可以轻松检查或扩展。 此外,Jython提供了一组抽象的基本调试类,以允许在此框架上构建其他调试器,例如GUI调试器。

要启动调试器,请运行以下命令:

c:\>jython c:\jython-2.1\lib\pdb.py .py

Jython调试会话示例

在调试器提示“(Pdb)”之后输入调试器命令。 这是一个使用factor.py模块的示例调试会话(请参见阶乘引擎:factor.py ):

C:\Articles>jython \jython-2.1\lib\pdb.py factor.py
> C:\Articles\(0)?()
(Pdb) step
> C:\Articles\(1)?()
(Pdb) step
> C:\Articles\factor.py(0)?()
(Pdb) list 67
 62             try:
 63                 print "For", value, "result =", 
fac.calculate(value)
 64             except ValueError, e:
 65                 print "Exception -", e
 66
 67         doFac(-1)
 68         doFac(0)
 69         doFac(1)
 70         doFac(10)
 71         doFac(100)
 72         doFac(1000)
(Pdb) tbreak 67
Breakpoint 1 at C:\Articles\factor.py:67
(Pdb) continue
factor.py running...
Deleted breakpoint 1
> C:\Articles\factor.py(67)?()
-> doFac(-1)
(Pdb) next
For -1 result = Exception - only positive integers supported: -1
> C:\Articles\factor.py(68)?()
-> doFac(0)
(Pdb) next
For 0 result = 1
> C:\Articles\factor.py(69)?()
-> doFac(1)
(Pdb) next
For 1 result = 1
> C:\Articles\factor.py(70)?()
-> doFac(10)
(Pdb) next
For 10 result = 3628800
> C:\Articles\factor.py(71)?()
-> doFac(100)
(Pdb) next
For 100 result = 
93326215443944152681699238856266700490715968264381621468592963895217599
99322991560894146397615651828625
3697920827223758251185210916864000000000000000000000000
> C:\Articles\factor.py(72)?()
-> doFac(1000)
(Pdb) next
For 1000 result = 402387260077 ... many other digits deleted ...
0000000000000000000000
--Return--
> C:\Articles\factor.py(72)?()->None
-> doFac(1000)
(Pdb) next
--Return--
> C:\Articles\(1)?()->None
(Pdb) next
C:\Articles>

要了解有关使用Jython调试器进行调试的更多信息,请参见附录C:Jython调试器命令 。

Jython分析器

有时您可能会注意到Jython程序的运行时间超出了预期。 您可以使用Jython探查器来找出程序中哪些部分花费的时间最长并对其进行优化。 探查器可让您探查整个程序或单个功能。

这是一个示例运行, factor.py程序进行了概要分析(请参阅阶乘引擎:factor.py ):

c:\>jython \jython-2.1\lib\profile.py \articles\factor.py

\articles\factor.py running...
For -1 result = Exception - only positive integers supported: -1
For 0 result = 1
For 1 result = 1
For 10 result = 3628800
For 100 result = 
93326215443944152681699238856266700490715968264381621468592963895217599
99322991560894146397615651828625369792082722375825118521091686400000000
0000000000000000
For 1000 result = 402387260077 ... many other digits deleted ...
0000000000000000000000

         237 function calls (232 primitive calls) in 0.250 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.130    0.130    0.240    0.240 :0(?)
        1    0.000    0.000    0.110    0.110 factor.py:0(?)
      220    0.010    0.000    0.010    0.000 \
factor.py:27(fireListeners)
        6    0.060    0.010    0.070    0.012 factor.py:34(calculate)
        1    0.000    0.000    0.000    0.000 factor.py:5(Factorial)
        1    0.000    0.000    0.000    0.000 factor.py:6(__init__)
      6/1    0.040    0.007    0.110    0.110 factor.py:61(doFac)
        1    0.010    0.010    0.250    0.250 \
profile:0(execfile('\\articles\\factor.py'))
        0    0.000             0.000          profile:0(profiler)

从此运行中,您可以看到(除了初始启动代码之外)大部分的编程时间都由calculate函数使用。 有关分析的详细信息,请参阅Jython的Python的参考手册 ,提供相关信息 。

断言

与C和Java语言(从1.4版开始)一样,Jython支持断言。 断言是程序正确运行所必须满足的条件; 如果它们不是真的,则程序可能无法正常运行。 通常,它们用于验证功能的输入值。 Jython对断言的支持来自以下assert语句的形式:

assert expression {, message}

请注意, expression是任何Jython表达式; 如果为false,则会引发exceptions.AssertionError异常。 如果message提供,它成为与异常关联的消息。 例如:

:
def myFunc(x):
    assert x >= 0, "argument %r must be >= 0" % x
    return fac(x)
:
z = myFunc(20)          # no exception raised

z = myFunc(-1)          # AssertionError raised

Jython中的Java支持

在Jython代码中使用Java服务

Jython最强大的功能之一是它与Java代码交互的能力。 Jython程序可以创建任何Java类的实例,并可以在任何Java实例上调用任何方法。 Jython还可以继承Java类,从而允许Java代码调用Jython代码。 Jython通过强大而透明地使用Java Reflection API(软件包java.lang.reflect ),使调用Java方法非常容易。

要完成本教程的这一部分,您需要熟悉Java语言并选择Java运行时API。 您应该了解Java平台上面向对象编程的基本概念,并熟悉Java数据类型,类,线程以及java.langjava.utiljava.iojavax.swing包。

注意:由于反射API已在1.4版中进行了高度优化,因此Jython在Java 1.4版及更高版本上的运行速度要快得多。

从Java代码调用Jython

如Inheritance中所示,Jython类可以继承 Java类。 子类化使扩展Java类(例如GUI组件)变得非常容易。 这允许Java代码调用Jython代码,而无需意识到它是Jython代码。 还可以在其他Java代码使用的Jython类中实现,如以下示例所示:

from java import util
class MyArray(util.ArrayList):  # subclass a Java class
    :
    def get (self, index):      # override the get method
        "@sig public java.lang.Object get(int index)"
      if 0 <= index < self.size:  
            return util.ArrayList.get(self, index)
        return None             # OutOfBounds now returns null

在由jythonc编译之后,可以在可以使用java.util.ArrayList实例的任何地方的Java代码中使用以上类。 请注意,在调用超类方法时,将self值作为参数传递。

从Jython调用Java类

除了子类化Java类之外,还可以直接在Jython中访问Java类。 例如,此代码序列:

from java.util import Date

 :

d = Date()   # now
print d, d.time, d.getTime()

将产生以下输出:

Tue Dec 02 14:44:02 CST 2003 1070397842496 1070397842496

使用Jython的JavaBean属性

在从Jython调用Java类的示例中,您可能已经注意到表达式d.timed.getTime()产生相同的结果。 这是因为他们做同样的事情。 Jython具有一个非常方便的功能,使JavaBean属性显示为Jython属性。 JavaBean属性是通过(通常)匹配以下形式的Java方法对来定义的,其中是属性的类型,而是属性的名称:

 get()

-- and --

void set( value)

例如,Java方法long getTime() { ... }void setTime(long t) { ... }定义了long属性time 。 因此,Jython引用d.time会自动动态地转换为Java表达式d.getTime()

Jython还可以设置属性,因此允许d.time = 1000000L Jython参考d.time = value会自动动态地转换为Java表达式d.setTime( value ) 应用此更改后, 来自Jython的Calling Java类的print语句将导致以下结果:

Wed Dec 31 18:01:40 CST 1969 100000 100000

Java对象上的调用方法

在Java对象上调用方法非常容易。 就像它们是Jython方法一样调用它们。 Jython自动在Jython和Java类型之间来回映射参数和返回值。 例如,以下是Jython的简短序列,该序列广泛使用Java类和方法:

1: from javax import swing 
2: import sys
3:
4: f = swing.JFrame(sys.argv[1], size=(200,200), 
5:                  defaultCloseOperation=swing.JFrame.EXIT_ON_CLOSE)
6: f.contentPane.add(swing.JLabel(sys.argv[2]))
7: f.visible = 1

此代码序列创建并显示一个GUI框架窗口。 脚本的第一个命令行参数将成为标题,第二个将成为内容文本。 第4行创建框架,并传递标题,所需的大小和关闭动作。 sizedefaultCloseOperation参数是如上所述的属性,因此,从Jython程序调用时,可以(非常方便地)在JFrame的构造函数中进行设置。 标题设置为JFrame等效于__init__方法的参数。 第6行访问JFramecontentPane属性,并调用其add方法添加一个JLabel以显示第二个参数。 第7行通过将其visible属性设置为1 (true)使该框架可见。

该GUI的示例如下所示:

覆盖Java方法和属性

如从Java代码调用Jython中所示,当在可以从Java语言调用的类中重写Java方法时,您需要提供签名信息。 这是通过文档注释完成的。 注释的第一行(以"@sig"开头)用作jythonc程序的指令(在第1部分中进行了讨论),以生成与Java兼容的方法签名。 例如,以下注释描述了使用Java语言的声明语法的get方法。 在签名中,类型必须完全合格。

"@sig public java.lang.Object get(int index)"

Jython不支持重载方法,重载方法是名称相同但参数数量和/或类型不同的方法。 相反,Jython支持默认参数和可变数量的参数,如果您从使用重载的Java类继承而要覆盖重载的方法,则可能会产生问题。 在Jython中,您必须定义基本方法并接受不同数量的参数。 考虑一个总是返回一个空白的InputStream的(不太实际)示例:

from java import io

class AlwaysBlank(io.InputStream):
    # covers all forms of read(...)
    def read(self, *args):
        if len(args) > 0: 
            # covers forms: int read(byte[])
            #               int read(byte[], int off, int len)
            return apply(io.InputStream.read, (self,) + args)
        else:
            # covers form: int read()
            return ord(' ')

该代码基于Jython主页上的示例。

Jython的Java数组

Jython支持Java样式的数组对象的创建。 数组主要用于将数组传递给Java方法以及从Java方法返回数组,但是它们是通用的,可以在纯Jython代码中使用。 数组元素是使用Java基本类型和类类型键入的。 数组的行为很像Jython列表,但是它们不能更改长度。

jarray模块提供了阵列支持。 jarray模块中的两个函数zerosarray用于创建数组。 数组函数将Jython序列映射到Java数组。 一些示例如下:

from jarray import zeros, array
from java import util
from javax import swing

a1 = zeros(100, 'i')            # an array of 100 int 0s
a2 = array([1,2,10,-5,7], 'i')  # an array of ints as listed

# an array of doubles 0.0 to 49.0
a3 = array([i * 1.0 for i in range(50)], 'd')  

a4 = zeros(10, util.Map)        # an array of 10 null Maps
a5 = array((swing.JFrame("F1"), # an array of 3 JFrames
            swing.JFrame("F2"), 
            swing.JFrame("F3")), swing.JFrame)
a6 = array("Hello", 'c')        # an array of characters

有关数组类型的字符代码的列表,请参见附录A:数组类型的字符代码。

Jython中的Java线程支持

Java线程

Java运行时广泛使用线程,线程用于处理GUI事件,执行异步I / O,实现异步处理等。

这很容易用Jython创建Java线程:只要创建的实例java.lang.Thread和小类java.lang.Runnable 有关示例,请参见GUI:fgui.py 。 您还可以使用以下形式的thread模块和函数从Jython函数中创建线程:

start_new_thread(function, args)

-- and --

exit()

start_new_thread函数在新的Java线程中运行function参数,并将args元组值传递给该函数。 可以在线程中使用exit函数结束它(通常作为if语句的目标)。

Java同步

使用Java或Jython线程开发多线程程序时,有时必须创建同步函数(或方法)。 同步函数是一次只能从一个线程调用的函数; 这意味着在第一个线程退出之前,其他线程将无法进入该函数。 Jython提供了synchronized模块和两个函数来创建同步函数。 这些函数具有以下形式:

make_synchronized(function)

-- and --

apply_synchronized(syncobj, function, pargs {, kwargs})

make_synchronized函数永久同步该function参数。 apply_synchronized函数会在syncobj上暂时进行同步,然后调用该function参数。

示例:使用make_synchronized

使用make_synchronized来通知事件非常简单,如下所示:

from synchronize import *
from java import lang

# define synchronization helpers

def waitForSignal (monitor):
    """ Wait until the monitor is signaled. """
    lang.Object.wait(monitor)
# replace with synchronized version; syncs on 1st argument
waitForSignal = make_synchronized(waitForSignal)

def notifySignal (monitor):
    """ Signal monitor. """
    lang.Object.notifyAll(monitor)
# replace with synchronized version; syncs on 1st argument
notifySignal = make_synchronized(notifySignal)

class Gui:           # GUI support
    :
    def doExit (self):
        self.visible = 0
        notifySignal(self)

if __name__ == "__main__":     # main code
    : 
    gui = Gui()
    : 
    print "Waiting until GUI exit requested..."
    waitForSignal(gui)
    print "Done"

Jython线程示例

这是使用Jython线程的示例。 该示例显示了一组生产者和使用者线程共享对公共缓冲区的访问。 我们将从共享缓冲区的定义开始,如下所示。

""" A Jython Thread Example. """

from java import lang 
from synchronize import *
from thread import start_new_thread
from sys import stdout

def __waitForSignal (monitor):
    apply_synchronized(monitor, lang.Object.wait, (monitor,))

def __signal (monitor):
    apply_synchronized(monitor, lang.Object.notifyAll, (monitor,))

def __xprint (stream, msg):
    print >>stream, msg

def xprint (msg, stream=stdout):
    """ Synchronized print. """
    apply_synchronized(stream, __xprint, (stream, msg))

class Buffer:
    """ A thread-safe buffer. """

    def __init__ (self, limit=-1):
        self.__limit = limit    # the max size of the buffer
        self.__data = []
        self.__added = ()       # used to signal data added
        self.__removed = ()     # used to signal data removed

    def __str__ (self):
        return "Buffer(%s,%i)" % (self.__data, self.__limit)

    def __len__ (self):
        return len(self.__data)

    def add (self, item):
        """ Add an item. Wait if full. """
        if self.__limit >= 0:
            while len(self.__data) > self.__limit:
                __waitForSignal(self.__removed)
        self.__data.append(item);
        xprint("Added: %s" % item)
        __signal(self.__added)

    def __get (self):
        item = self.__data.pop(0)
        __signal(self.__removed)
        return item

    def get (self, wait=1):
        """ Remove an item. Wait if empty. """
        item = None
        if wait:
            while len(self.__data) == 0:
                __waitForSignal(self.__added)
            item = self.__get()
        else:
            if len(self.__data) > 0: item = self.__get()
        xprint("Removed: %s" % item)
        return item
    get = make_synchronized(get)

生产者和消费者的定义

该示例的下一步是查看生产者和消费者定义,如下所示:

class Producer:
    def __init__ (self, name, buffer):
        self.__name = name
        self.__buffer = buffer

    def __add (self, item):
        self.__buffer.add(item)

    def __produce (self, *args):
        for item in args:
            self.__add(item)

    def produce (self, items):
        start_new_thread(self.__produce, tuple(items))

class Consumer:
    def __init__ (self, name, buffer):
        self.__name = name
        self.__buffer = buffer

    def __remove (self):
        item = self.__buffer.get()
        return item

    def __consume (self, count):
        for i in range(count):
            self.__remove()

    def consume (self, count=1):
        start_new_thread(self.__consume, (count,))

线程示例的试运行

最后,这是示例代码的试运行:

# all producers and consumer share this one
buf = Buffer(5)    

p1 = Producer("P1", buf)
p2 = Producer("P2", buf)
p3 = Producer("P3", buf)
p4 = Producer("P4", buf)
c1 = Consumer("C1", buf)
c2 = Consumer("C2", buf)

# create 6 items
p1.produce(["P1 Message " + str(i) for i in range(3)])
p2.produce(["P2 Message " + str(i) for i in range(3)])

# consume 20 items
for i in range(5):
    c1.consume(2)
    c2.consume(2)

# create 20 more items
p3.produce(["P3 Message " + str(i) for i in range(10)])
p4.produce(["P4 Message " + str(i) for i in range(10)])

# consume 4 items
c1.consume(2)
c2.consume(2)

# let other threads run
lang.Thread.currentThread().sleep(5000)

xprint("Buffer has %i item(s)left" % len(buf))

示例输出

生产者使用者示例产生以下结果(包装为两列以节省空间):

Added: P1 Message 0       Added: P3 Message 7       
Added: P1 Message 1       Removed: P3 Message 7     
Added: P1 Message 2       Added: P3 Message 8       
Added: P2 Message 0       Removed: P3 Message 8     
Added: P2 Message 1       Added: P3 Message 9       
Added: P2 Message 2       Removed: P3 Message 9     
Removed: P1 Message 0     Added: P4 Message 0       
Removed: P1 Message 1     Removed: P4 Message 0     
Removed: P1 Message 2     Added: P4 Message 1       
Removed: P2 Message 0     Removed: P4 Message 1     
Removed: P2 Message 1     Added: P4 Message 2       
Removed: P2 Message 2     Removed: P4 Message 2     
Added: P3 Message 0       Added: P4 Message 3       
Removed: P3 Message 0     Removed: P4 Message 3     
Added: P3 Message 1       Added: P4 Message 4       
Removed: P3 Message 1     Added: P4 Message 5       
Added: P3 Message 2       Added: P4 Message 6       
Removed: P3 Message 2     Added: P4 Message 7       
Added: P3 Message 3       Added: P4 Message 8       
Removed: P3 Message 3     Added: P4 Message 9       
Added: P3 Message 4       Removed: P4 Message 4     
Removed: P3 Message 4     Removed: P4 Message 5     
Added: P3 Message 5       Removed: P4 Message 6     
Removed: P3 Message 5     Removed: P4 Message 7     
Added: P3 Message 6       Buffer has 2 item(s)left  
Removed: P3 Message 6

与Java服务接口

创建界面

通常,您将需要在Jython代码中使用Java服务。 在这些情况下,您可以在每次需要使用给定服务时公开地进行操作,也可以将Java服务包装在Jython库函数中,然后在Jython代码中使用该函数。

推荐使用第二个选项,因为它封装并抽象了Java代码。

在Jython中包装Java服务

作为如何将Java服务包装在Jython库函数中的示例,我们将看一下JavaUtils.py模块摘录。 下面的代码介绍了JavaUtils模块。 请参阅本教程的第1部分 ,以刷新有关模块的信息。

""" This module defines several functions to ease interfacing with Java code."""

from types import *

from java import lang
from java import util
from java import io

# only expose these
__all__ = ['loadProperties', 'getProperty', 
           'mapToJava', 'mapFromJava', 'parseArgs']

访问Java属性文件

您通常将需要访问Java属性文件以获取配置信息。 Jython允许您loadProperties使用loadPropertiesgetProperty函数,如下所示:

def loadProperties (source):
    """ Load a Java properties file into a Dictionary. """
    result = {}
    if type(source) == type(''):    # name provided, use file
        source = io.FileInputStream(source)
    bis = io.BufferedInputStream(source)
    props = util.Properties()
    props.load(bis) 
    bis.close()
    for key in props.keySet().iterator():
        result[key] = props.get(key)
    return result

def getProperty (properties, name, default=None):
    """ Gets a property. """
    return properties.get(name, default)

属性文件示例

因此,例如,如果您要使用访问Java属性文件中的功能,如下所示

import sys
file = sys.argv[1]
props = loadProperties(file)
print "Properties file: %s, contents:" % file 
print props
print "Property %s = %i" % ('debug', int(getProperty(props, 'debug', '0')))

具有的属性文件内容

# This is a test properties file
debug = 1
error.level = ERROR
now.is.the.time = false

那么结果输出将是:

Properties file: test.properties, contents:
{'error.level': 'ERROR', 'debug': '1', 'now.is.the.time': 'false'}
Property debug = 1

映射Java类型

有时您需要在Jython中创建纯Java对象(例如,当您需要创建对象以通过网络发送到基于Java的服务器时,或者当您需要将该对象传递给类型敏感的Java服务时,例如以及Swing表单元格值)。 要将Jython内置类型转换为Java类型(反之亦然),请使用以下示例中的功能( Jython中包装Java服务的JavaUtils.py模块摘录的延续):

def mapMapFromJava (map):
    """ Convert a Map to a Dictionary. """
    result = {}
    iter = map.keySet().iterator()
    while iter.hasNext():
        key = iter.next()
        result[mapFromJava(key)] = mapFromJava(map.get(key))
    return result

def mapCollectionFromJava (coll):
    """ Convert a Collection to a List. """
    result = []
    iter = coll.iterator();
    while iter.hasNext():
        result.append(mapFromJava(iter.next()))
    return result

def mapFromJava (object):
    """ Convert a Java type to a Jython type. """
    if object is None: return object
    if   isinstance(object, util.Map):        
        result = mapMapFromJava(object)
    elif isinstance(object, util.Collection): 
        result = mapCollectionFromJava(object)
    else:                                     
        result = object
    return result

def mapSeqToJava (seq):
    """ Convert a sequence to a Java ArrayList. """
    result = util.ArrayList(len(seq))
    for e in seq:
        result.add(mapToJava(e));
    return result

def mapDictToJava (dict):
    """ Convert a Dictionary to a Java HashMap. """
    result = util.HashMap()
    for key, value in dict.items():
        result.put(mapToJava(key), mapToJava(value))
    return result

def mapToJava (object):
    """ Convert a Jython type to a Java type. """
    if object is None: return object
    t = type(object)
    if   t == TupleType or t == ListType:  
        result = mapSeqToJava(object)
    elif t == DictType:  
        result = mapDictToJava(object)
    else:                
        result = object
    return result

使用mapToJava ,可以将这些类型写入java.io.ObjectOutputStream java.io.ObjectInputStream读取对象后,可以使用mapFromJava将对象转换回Jython类型。

请注意,这些方法支持一组有限但广泛使用的内置Jython类型。 Jython自动转换类似数值的类型,例如数字和字符串。 不支持用户定义的类。

映射Java类型,续

为了继续该示例,将在上一节中讨论映射功能的以下用法,如下所示:

data = (1,2,3, [1,2,3], [c for c in "Hello!"], "Hello!", {1:'one', 2:'two'})
print "data:", data
toJava = mapToJava(data)
print "toJava:", toJava
fromJava = mapFromJava(toJava)
print "fromJava:", fromJava

print

print "type(%s)=%s" % ("data", type(data))
print "type(%s)=%s" % ("toJava", type(toJava))
print "type(%s)=%s" % ("fromJava", type(fromJava))

印刷品:

data: (1, 2, 3, [1, 2, 3], ['H', 'e', 'l', 'l', 'o', '!'], 'Hello!', \
    {2: 'two', 1: 'one'})
toJava: [1, 2, 3, [1, 2, 3], [H, e, l, l, o, !], Hello!, {2=two, 1=one}]
fromJava: [1, 2, 3, [1, 2, 3], ['H', 'e', 'l', 'l', 'o', '!'], 'Hello!', \
    {2: 'two', 1: 'one'}]

type(data)=org.python.core.PyTuple
type(toJava)=org.python.core.PyJavaInstance
type(fromJava)=org.python.core.PyList

注意, PyTuple变成了PyJavaInstance ,然后变成了PyList 还要注意, toJava表单的格式不同。 这是因为它是一个Java对象,是由Java toString()方法而不是Jython repr()函数打印的。 PyJavaInstance是Jython将传递给Java API的一种类型。 最后,请注意, datafromJava值相同,除了元组现在是等效列表。 有关Jython类型的更多信息,请参见附录L:Jython类型摘要 。

解析命令行

通常,与简单使用sys.argv提供的内容相比,您需要对命令参数进行更多处理。 parseArgs函数可用于获取任何命令行参数,作为位置参数序列(的元组)和开关字典。

因此,继续JavaUtils.py模块摘录(分别来自Jython的Wrapping Java服务和Mapping Java类型 ),我们将看到:

def parseArgs (args, validNames, nameMap=None):
    """ Do some simple command line parsing. """
    # validNames is a dictionary of valid switch names -
    #   the value (if any) is a conversion function
    switches = {}
    positionals = []
    for arg in args:
        if arg[0] == '-':               # a switch
            text = arg[1:]
            name = text; value = None
            posn = text.find(':')       # any value comes after a :
            if posn >= 0:
                name = text[:posn]
                value = text[posn + 1:]
            if nameMap is not None:     # a map of valid switch names
                name = nameMap.get(name, name)
            if validNames.has_key(name):   # or - if name in validNames:
                mapper = validNames[name]
                if mapper is None: switches[name] = value
                else:              switches[name] = mapper(value)
            else:
                print "Unknown switch ignored -", name

        else:                           # a positional argument
            positionals.append(arg)
    return positionals, switches

此功能可以按如下方式使用(在文件parsearg.py ):

from sys import argv
from JavaUtils import parseArgs

switchDefs = {'s1':None, 's2':int, 's3':float, 's4':int}
args, switches = parseArgs(argv[1:], switchDefs)
print "args:", args
print "switches:", switches

对于命令c:\>jython parsearg.py 1 2 3 -s1 -s2:1 ss -s4:2 ,它显示:

args: ['1', '2', '3', 'ss']
switches: {'s4': 2, 's2': 1, 's1': None}

Jython字符串处理

字符串操作和函数

与大多数脚本语言(如Perl和Rexx)一样,Jython对操作字符串也有广泛的支持。 此支持通常与Java语言提供的支持相似,但通常更简单易用。 在本节中,我们将讨论一些更常用的字符串操作和函数。 请参阅本教程的第1部分和Python库参考,以了解有关字符串方法的更多信息。

在接下来几节的示例中,我将使用以下值:

name ="Barry Feigenbaum"
addr = '12345 Any Street"
v1 = 100; v2 = v1 * 1.5; v3 = -v2; v4 = 1 / v2
s1 = "String 1"; s2 = "String 2"
sent = "The rain in Spain falls mainly on the plain."

获取对象的字符串形式

要获取任何值或表达式(即对象)的字符串表示形式,请使用以下功能之一:

  • str(expr)创建一个以人为本的字符串。
  • repr(expr)`expr`在可能的情况下创建一个面向计算机的字符串, eval函数可以从中重新创建该值。

请注意,对于许多类型(包括基本类型), str(x)repr(x)生成相同(或非常相似)的字符串。

基本的字符串操作

字符串是一种内置类型,既用作值又用作方法的对象。 Strings support the basic operations of concatenation, indexing, containment, and formatting, as well as the other operations of immutable sequences. We'll go over the basic string operations, starting with concatenation.

We use the plus ( + ) operator to concatenate two strings. For example, the following line:

print "abc" + "xyz"

prints: abcxyz .

To select a character or characters (that is, a substring) from a string you use indexing. For example: "abcxwy"[2] yields c , while "abcxwy"[2:4] yields cx .

Many of the string functions test conditions, thus they are often used in conjunction with the if and while statements. Here's an example of how we could use containment testing to see if a character were contained in a string:

if ' ' in name: print "space found"

-- or --

if 'q' not in sent: print "q not found"

In addition to testing conditions , strings also support methods to test the nature of the string. These are islower , isupper , isalnum , isnum , isalpha , isspace , and istitle . These methods test to see if all the characters in the strings meet these conditions.

Additional methods

Strings support several methods that allow you to find and edit sub-strings, change case, and a host of other actions. To find a string in another string use the find / rfind or startswith / endswidth methods. 例如:

if name.find(' ') >= 0: print "space found"

-- or --

if name.find("Jones") < 0: print "Jones not in name"

Sometimes you need to edit the content of a string, for example to change its case or insert or remove text from it. Jython supplies several methods to do this. To change case, Jython has the lower , upper , swapcase , title , and capitalize methods. To change the text of a string, use the replace method. For example, to match strings often you want to ignore case or you may want to replace sub-strings:

if  s1.lower() == s2.lower(): print "equal"

-- or --

newaddr = addr.replace("Street", "St.")

Often strings have extra blanks around them that are not important, such as when the string is entered by a user. To remove these extra blanks use the lstrip , rstrip , or strip methods. For example, to match a command entered by a user:

cmd = raw_input("Enter a command")
if cmd.lstrip.startswith("run "): 
    print "run command found"

Often you need to break strings into parts, such as the words in a sentence or join multiple strings into one string. Jython supports the split , splitlines , and join functions to do this. The split method splits a line into words, while splitlines splits a file of lines into separate lines. The join method reverses split . You can also join strings by concatenation as discussed above. For example, to extract the words from a sentence and then rebuild the sentence use:

words = sent.split(' ')   # use space to separate words
sent2 = ' '.join(words)   # use space between words

Formatting program variables

It is very easy to format local or global variables using the modulus (%) operator. The locals and globals functions return dictionaries for all the local and global (respectively) variables. 例如:

fname = "Barry"; lname = "Feigenbaum"
address = "1234 any St."
city = "Anytown"; state = "TX"; zip = "12345"
age = 30
children = 3
  :
print "Hello %(fname)s from %(city)s, %(state)s." % locals()

prints Hello Barry from Anytown, TX.

See Appendix J: Formatting strings and values for more about formatting program variables.

Format operator examples

Below are some format (%) operator examples. See Appendix J: Formatting strings and values for more examples.

表达 结果
"Hello %s" % "Barry" Hello Barry
"Count: %i, " "Avg Cost: $%.2f; " "Max Cost: $%.2f" % (10, 10.5, 50.25) Count: 10, Avg Cost: $10.50; Max Cost: $50.25
"This is %i%%" % 10 This is 10%
"My name is %(first)s %(last)s!" % {'last':'Feigenbaum', 'first':'Barry', 'mi':'A'} My name is Barry Feigenbaum!

Using C-style printf

For those familiar with C's printf("... %x ...", v1, ..., vN) function, a similar but enhanced service can be added in Jython, as shown here:

def printf(stream, format, *pargs, **kwargs):

                        # seePrinting to files for more information
    if   pargs:
        print >>stream, format % pargs
    elif kwargs:
        print >>stream, format % kwargs
    else:
        print >>stream, format

这里

Using the above printf function definition, the following examples:

from sys import stdout

printf(stdout, "%s is %.1f years old and has %i children", 
       fname, age, children)

printf(stdout, "The %(name)s building has %(floors)d floors", 
       floors=105, name="Empire State")

printf(stdout, "Hello World!")

print:

Barry is 30.0 years old and has 3 children
The Empire State building has 105 floors
Hello World!

Pretty printing

You can use the pprint module functions, in particular the pformat function, to print complex data structures in a formatted form. For example, this code:

data = [[1,2,3], [4,5,6],{'1':'one', '2':'two'}, 
        "jsdlkjdlkadlkad", [i for i in xrange(10)]]
print "Unformatted:"; print data

print

from pprint import pformat
print "Formatted:"; print pformat(data)

prints the following:

Unformatted:
[[1, 2, 3], [4, 5, 6], {'2': 'two', '1': 'one'}, \
    'jsdlkjdlkadlkad', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]

Formatted:
[[1, 2, 3],
 [4, 5, 6],
 {'2': 'two', '1': 'one'},
 'jsdlkjdlkadlkad',
 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]

Using string functions

As an example of using the string operations from String operations and functions , the justify.py program (listed below) takes paragraphs of input and formats them into pages. The text may be left-, center-, right-aligned, or justified. Page margins may be specified. Header and/or footer text may be supplied.

See Related topics for some sample results of using this program.

import sys

def stripLines (lines):
    """ Removed extra whitespace (that is, newlines). """
    newlines = []
    for line in lines:
        line = line.strip()
        newlines.append(line)
    return newlines

def splitParagraphs (lines):
    """ Splits a set of lines into paragraphs.  """
    paras = []
    para = ""
    for line in lines:
        if len(line) > 0:       # in paragraph
            para += ' ' + line
        else:                   # between paragraphs
            para = para.strip()
            if len(para) > 0:
                paras.append(para)
                para = ""
    return paras

class Formatter:
    """ Formats and prints paragraphs.  """

    def __init__ (self, stream, pagelen=66, linewidth=85, 
                        lmargin=10, rmargin=10, pindent=5,
                        alignment="justify",
                        headers=None, footers=None):
        self.stream = stream        # stream to print on

        # format settings
        self.pagelen = pagelen 
        self.pindent = pindent 
        self.linewidth = linewidth  
        self.lmargin = lmargin    
        self.rmargin = rmargin    
        self.headers = headers    
        self.footers = footers    
        self.alignment = alignment

        self.pagecount = 1         # current page
        self.linecount = 0         # current line
    
    def genLine (self, line):
        print >>self.stream, line
        self.linecount += 1

    def outputLine (self, line):
        self.testEndPage()
        if not (self.linecount == 0 and len(line) == 0):
            self.genLine(line)
    
    def newPage (self):
        if self.headers:
            self.outputHeader()
    
    def padPage (self):
        while self.linecount < self.pagelen:
            self.genLine("")
    
    def endPage (self):
        if self.footers:
            if len(self.footers) + self.linecount < self.pagelen:
                self.padPage()
            self.outputFooter()
        else:
            if self.linecount < self.pagelen:
                self.padPage()
        self.linecount = 0
        self.pagecount += 1
        self.genLine('-' * 20)
    
    def testEndPage (self):
        if self.footers:
            if len(self.footers) + 1 + self.linecount >= self.pagelen:
                self.endPage()
                self.newPage()
        else:
            if self.linecount >= self.pagelen:
                self.endPage()
                self.newPage()

    def padLine (self, line, firstline=0, lastline=0):
        """ Add spaces as needed by alignment mode.  """

        if   self.alignment == "left":
            adjust = firstline * self.pindent
            #line = line

        elif self.alignment == "center":
            adjust = 0
            pad = self.linewidth - adjust - len(line)
            line = ' ' * (pad / 2) + line

        elif self.alignment == "right":
            adjust = 0
            pad = self.linewidth - adjust - len(line)
            line = ' ' * pad + line

        elif self.alignment == "justify":
            adjust = firstline * self.pindent
            pad = self.linewidth - adjust - len(line)
            line = ""

            # add 1+ spaces between words to extend line
            words = line.split()
            xpad = pad                       
            for word in words:
                line += word + ' '
                if not lastline and xpad > 0:
                    line += ' '  * (pad / len(words) + 1)
                    xpad -= 1
            line = line.strip()

        return ' ' * adjust + line 

    def format (self, line, firstline=0, lastline=0):
        # indent by left margin
        return ' ' * self.lmargin + \
               self.padLine(line.strip(), firstline, lastline)

    def formatParagraph (self, para):
        lcount = 0
        adjust = self.pindent
        line = ""

        # process by words
        words = para.split(' ')
        for word in words:
            line += ' '
            # about to get too long
            if len(line) + len(word) > self.linewidth - adjust:
                line = self.format(line, lcount == 0, 0)
                self.outputLine(line)
                line = "" 
                lcount += 1
                adjust = 0
            line += word
        # output last (only) line
        if len(line) > 0:
            line = self.format(line, lcount == 0, 1)
            self.outputLine(line)

    def outputHeader (self):
        for line in self.headers:
            self.genLine(' ' * self.lmargin + line.center(self.linewidth))
        self.genLine("")
    
    def outputFooter (self):
        self.genLine("")
        for line in self.footers:
            self.genLine(' ' * self.lmargin + line.center(self.linewidth))
    
    def outputPages (self, paras):
        """ Format and print the paragraphs. """
        self.newPage()
        for para in paras:
            self.formatParagraph(para)
            self.outputLine("")
        self.endPage()

Processing regular expressions

About regular expressions

As an extension to the find and replace functions described in String operations and functions , Jython supports regular expressions. Regular expressions (RE) are strings that contain plain match text and control characters and provide an extremely powerful string search and replace facility. Jython supports (at least) the following forms of regular expressions:

  • re module is a built-in part of Jython.
  • Java works if you're running Jython on Java 1.4 or above.
  • Apache ORO works if you add the ORO package to your CLASSPATH .

Regular expression formats

The simplest RE is an exact string to match. More complex REs include special control characters. The control characters allow you to create patterns of matching strings. For more information on RE syntax and options see Appendix H: Regular expression control characters and the Python Library Reference .

[Jennette, from Barry: We need to get the spacing right in this table, I have multiple nbsp's that show as only one space.]-->

Below are some example REs and the strings they match:

Control character Regular expression 火柴 Does not match
-- none -- abc abc b
aabc
abcc
- any character 交流电 abc
axc
交流电
交流电
abbc
* - optional repeating subpattern a.*c abc
axc
交流电
交流电
axxxxc
A B C D
- optional subpattern a.?c abc 交流电
aabc
+ - required repeating subpattern a.+c abc
abbc
axxc
交流电
A B C D
...|... - choice of subpattern abc|def abcef
abdef
abef
abcdef
(...) - grouping a(xx)|(yy)c axxc
ayyc
axxyyc
axc
ayc
(...)* - repeating grouping a(xx)*c 交流电
axxc
axxxxc
axxbxxc
(...)+ - required repeating grouping a(xx)+c axxc
axxxxc
交流电
axxbxxc
\c - match a special character \.\?\*\+ .?*+ ?.*+
A B C D
\s - matches white space a\s*z z
z
a z
za
za
abyz

Regular expressions functions

The Jython re module provides support for regular expressions. re 's primary functions are findall , match , and search to find strings, and sub and subn to edit them. The match function looks at the start of a string, the search function looks anywhere in a string, and the findall function repeats search for each possible match in the string. search is (by far) the most used of the regular expression functions.

Here are some of the most common RE functions:

功能 注释)
match(pattern, string {, options}) Matches pattern at the string start
search(pattern, string {, options}) Matches pattern somewhere in the string
findall(pattern, string) Matches all occurrences of pattern in the string
split(pattern, string {, max}) Splits the string at matching points and returns the results in a list
sub(pattern, repl, string {, max}) Substitutes the match with repl for max or all occurrences; returns the result
subn(pattern, repl, string {, max}) Substitutes the match with repl for max or all occurrences; returns the tuple (result, count)

Note that the match ing functions return None if no match is found. Otherwise the match functions will return a Match object from which details of the match can be found. See the Python Library Reference for more information on Match objects.

Two function examples

Let's take a look at some examples of regular expressions functions in action:

import re

# do a fancy string match
if re.search(r"^\s*barry\s+feigenbaum\s*$", name, re.I):
   print "It's Barry alright"

# replace the first name with an initial
name2 = re.sub(r"(B|b)arry", "B.", name)

If you are going to use the same pattern repeatedly, such as in a loop, you can speed up execution by using the compile function to compile the regular expression into a Pattern object and then using that object's methods, as shown here:

import re
patstr = r"\s*abc\s*"
pat = re.compile(patstr)
# print all lines matching patstr
for s in stringList:
    if pat.match(s, re.I): print "%r matches %r" % (s, patstr)

Regular expression example: Grep

The following simplified version of the Grep utility (from grep.py ) offers a more complete example of a Jython string function.

""" A simplified form of Grep. """

import sys, re

if len(sys.argv) != 3:
    print "Usage: jython grep.py  "
else:
    # process the arguments
    pgm, patstr, filestr = sys.argv
    print "Grep - pattern: %r file: %s" % (patstr, filestr)
    pat = re.compile(patstr)  # prepare the pattern


                        # seeFile I/O in Jython
                     for more information
    file = open(filestr)      # access file for read
    lines = file.readlines()  # get the file
    file.close()

    count = 0
    # process each line
    for line in lines:
        match = pat.search(line)    # try a match
        if match:                   # got a match
            print line
            print "Matching groups: " + str(match.groups())
            count += 1
    print "%i match(es)" % count

When run on the words.txt file from File I/O in Jython , the program produces the following result:

C:\Articles>jython grep.py "(\w*)!" words.txt
Grep - pattern: '(\\w*)!' file: words.txt
How many times must I say it; Again! again! and again!

Matched on: ('Again',)
Singing in the rain! I'm singing in the rain! \
    Just singing, just singing, in the rain!

Matched on: ('rain',)
2 match(es)

File I/O in Jython

Using files

In addition to the Java platform's file-related APIs (packages java.io and, in Java 1.4, java.nio ), Jython provides simple yet powerful access to files using the File type and services in the os , os.path , and sys modules. (See Appendix F: The os module , Appendix G: The os.path module , Appendix E: The sys module and the Python Reference Manual for more details on the os and os.path packages.)

We'll start with a look at some basic file-access operations. A File object is created using the built-in open function, shown below, where path is the path to the file, mode is the access mode string, and size is the suggested buffer size:

file = open(path {, mode {, size}})

The mode string has the following syntax: (r|w|a){+}{b} ; the default mode is r . Here is a listing of all the available access mode strings:

  • r : read
  • w : write
  • a : append to the end of the file
  • + : update
  • b : binary (vs. text)

The name of the file is accessed through the name attribute. The mode of the file is accessed through the mode attribute.

File access methods

Files support the following methods:

方法 注释)
close() Flush and close an open file
flush() Outputs any buffered data
read({size}) Reads up to size (or the whole file)
readline({size}) Read a line (including ending '\n') up to size
readlines() Reads the file and returns a list of lines (including ending '\n')
seek(offset {, mode}) Seek to a position, mode: 0 - start of file, 1 - current offset, 2 - end of file
tell() Return the current offset
truncate({size}) Truncate (delete extra content) to current offset or specified size
write(string) Write the string to a file. To write lines, end the string in '\n'
writelines(lines) Write the list as a set of strings. To write lines, end each string in '\n'

Simple file processing examples

We'll look at a couple of simple file processing examples, starting with the file copy program below:

import sys

f = open(sys.argv[1], "rb")    # open binary for reading
bin = f.read()
f.close()
f = open(sys.argv[2], "wb")    # open binary (truncated) for write
f.write(bin)
f.close()

And here is a text file sort procedure:

import sys

f = open(sys.argv[1], "r")    # read the file by lines
lines = f.readlines()
f.close()
lines.sort()                  # sort and print the lines
print "File %s sorted" % f.name
print lines

A word-counting program in Jython

As a more complete example of file processing, study the following word-counting program:

import sys

def clean (word):
    """ Remove any punctuation and map to a common case. """
    word = word.lower()
    # remove any special characters
    while word and word[-1] in ".,;!": word = word[:-1]
    while word and word[0] in ".,;!": word = word[1:]
    return word

words = {}  # set of unique words and counts

if len(sys.argv) != 2:
    print "Usage: jython wcount.py "
else:
    file = open(sys.argv[1])  # access file for read
    lines = file.readlines()  # get the file
    file.close()

    # process each line
    for line in lines:
        # process each word in the line
        for word in line.split():
            word = clean(word)
            words[word] = words.get(word, 0) + 1   # update the count

    # report the results
    keys = words.keys()
    keys.sort()
    for word in keys:
        print "%-5i %s" % (words[word], word)

Output of words.txt

Given the following input file ( words.txt )

Now is the time for all good men to come to the aid of their country.
The rain in Spain falls mainly on the plain.
How many times must I say it; Again! again! and again!
Singing in the rain! I'm singing in the rain! \
    Just singing, just singing, in the rain!

the word-counting program (from A word-counting program in Jython ) would return the following results (wrapped into two columns to save space):

3     again             1     many       
1     aid               1     men        
1     all               1     must       
1     and               1     now        
1     come              1     of         
1     country           1     on         
1     falls             1     plain      
1     for               4     rain       
1     good              1     say        
1     how               4     singing    
1     i                 1     spain      
1     i'm               7     the        
4     in                1     their      
1     is                1     time       
1     it                1     times      
2     just              2     to         
1     mainly

The word-counting program in Java code

Let's take a look at the word-counting script re-implemented in the Java language. Notice the extensive use of types in declarations and type-casts in the assignment statements. As you can see, the Java code is significantly larger (approximately two times) and arguably far more cryptic.

import java.io.*;
import java.util.*;
import java.text.*;

public class WordCounter
{
    protected static final String specials = ".,;!";

    /** Remove any punctuation and map to a common case. */
    protected static String clean(String word) {
        word = word.toLowerCase();
        // remove any special characters
        while (word.length() > 0 && 
               specials.indexOf(word.charAt(word.length() - 1)) >= 0) {
            word = word.substring(0, word.length() - 1);

        }
        while (word.length() > 0 && 
               specials.indexOf(word.charAt(0)) >= 0) {
            word = word.substring(1);
        }
        return word;
    }

    protected static Map words = new HashMap();

    public static void main(String[] args) throws IOException {
        if (args.length != 1) {
            System.out.println("Usage: java WordCounter ");
        }
        else {                               
            // access file for read
            FileInputStream fis = new FileInputStream(args[0]);
            DataInputStream dis = new DataInputStream(fis);
            List lines = new ArrayList();
            // get the file
            for (String line = dis.readLine(); 
                 line != null; 
                 line = dis.readLine()) {
                lines.add(line);  
            }
            dis.close();

            // process each line
            for (int i = 0; i < lines.size(); i++) {
                String line = (String)lines.get(i);
                System.out.println("Processing: " + line);
                String[] xwords = line.split("\\s+");
                for (int w = 0; w < xwords.length; w++) {
                    String word = clean(xwords[w]);
                    if (word.length() > 0) {
                        Integer count = (Integer)words.get(word);
                        if (count == null) {
                            count = new Integer(0);
                        }
                        // update the count
                        words.put(word, 
                                  new Integer(count.intValue() + 1));  
                    }
                }
            }

            // report the results
            String[] keys = (String[])words.keySet().
                                 toArray(new String[words.size()]);
            Arrays.sort(keys);

            MessageFormat form = new MessageFormat(
                            "{0,number, #########0} {1}");
            for (int i = 0; i < keys.length; i++) {
                System.out.println(form.format(
                          new Object[] {words.get(keys[i]), keys[i]}));
            }
        }
    }
}

Printing to files

The print statement can print to a file by use of the " >> " operator. By default it prints to the console (actually the value of sys.stdout ). For example, the following commands are equivalent:

print "Hello World!"
import sys
print >>sys.stdout, "Hello world!"

Jython allows alternate target files. For example, to print to the standard error stream use:

print >>sys.stderr, "Hello world!"

To print to a file use:

f = open("myfile", "w")
for i in range(10):
    print >>f, "Line", i
f.close()

And to add to the end of a file use:

f = open("myfile", "a")
print >>f, "Added line"
f.close()

Saving objects persistently

Sometimes you may want to save an object persistently (beyond the lifetime of the program that creates it) or send it to another application. To do this you need to serialize (or pickle ) the object so it can be placed in a file or on a stream. You then need to de-serialize (or un-pickle ) the object to use it again. Jython provides a module, pickle , that makes this very easy. The pickle module contains the following useful functions:

功能 注释)
load(file) Returns an object re-created from a previously created image in a file.
loads(string) Returns an object recreated from a previously created image in a string.
dump(object, file {, bin}) Stores an object image into a file. If bin is omitted or false, use a text representation; else a binary representation (which is typically smaller).
dumps(object{, bin}) Returns a string containing the image of the object. If bin is omitted or false, use a text representation; else a binary representation (which is typically smaller).

A pickling example

Here's an example of pickle at work. The following code sequence

import pickle

class Data:
    def __init__ (self, x, y):
        self.__x = x
        self.__y = y

    def __str__ (self):
        return "Data(%s,%s)" % (self.__x, self.__y)

    def __eq__ (self, other):
        return self.__x == other.__x and self.__y == other.__y


data = Data(10, "hello")

file = open("data.pic", 'w')
pickle.dump(data, file)
file.close()

file = open("data.pic", 'r')
newdata = pickle.load(file)
file.close()

print "data:", data
print "newdata:", newdata
print "data is newdata:", data is newdata
print "data == newdata:", data == newdata

prints this:

data: Data(10,hello)
newdata: Data(10,hello)
data is newdata: 0 (false)
data == newdata: 1 (true)

The file created is in (semi-)readable plain text. For example, the above code created the file data.pic :

(i__main__
Data
p0
(dp1
S'_Data__y'
p2
S'hello'
p3
sS'_Data__x'
p4
I10
sb.

Note that Jython cannot pickle objects that are Java objects, reference Java objects, or subclass Java classes. To do this you need to use the java.io.ObjectOutputStream and java.io.ObjectInputStream classes.

Object shelves

As shown in the previous section, Jython can store objects into a file. Using a file per object can cause problems (that is, it can waste space and you will need to name each file). Jython supports a file that can hold multiple objects, called a shelf . A shelf acts much like a persistent dictionary. To create shelves, use the open function of module shelve . For example, the following code:

import shelve, sys

def printshelf (shelf, stream=sys.stdout):  # print the entries in a shelf
    for k in shelf.keys():
        print >>stream, k, '=', shelf[k]

def clearshelf (shelf):                     # remove all keys in the shelf
    for k in shelf.keys():
        del shelf[k]

# create shelf
shelf = shelve.open("test.shelf")
clearshelf(shelf)
shelf["x"] = [1,2,3,4]
shelf["y"] = {'a':1, 'b':2, 'c':3}
printshelf(shelf)
shelf.close()

print
# update shelf
shelf = shelve.open("test.shelf")
printshelf(shelf)
print
shelf["z"] = sys.argv[1]
printshelf(shelf)
shelf.close()

print
# verify shelf persistent
shelf = shelve.open("test.shelf")
printshelf(shelf)
shelf.close()

produces this output (with argument "This is a test string"):

x = [1, 2, 3, 4]
y = {'b': 2, 'a': 1, 'c': 3}

x = [1, 2, 3, 4]
y = {'b': 2, 'a': 1, 'c': 3}

x = [1, 2, 3, 4]
z = This is a test string
y = {'b': 2, 'a': 1, 'c': 3}

x = [1, 2, 3, 4]
z = This is a test string
y = {'b': 2, 'a': 1, 'c': 3}

Note that the open function produces two files based on the file name passed to open :

  • .dir is a directory into the persistent data
  • .dat is the saved persistent object data

A simple Swing GUI

The Factorial Calculator

We'll close this second installment of the "Introduction to Jython" tutorial with a complete program that encompasses many of the details we have so far discussed. The Factorial Calculator is a GUI application written entirely in Jython. It calculates the value of x! (x factorial) for any positive integer value. Because x! can be very large, this example takes advantage of Jython's ability to process very large integers. Calculations for large values of x (say, > 10000) can take several minutes, so the user interface includes a progress bar and a Cancel button to interrupt a calculation.

In the sections that follow, you can see the two most essential components of the Factorial Calculator: the class that supplies the factorial calculation engine, and the set of classes that comprise the GUI. The complete, runnable code for the Factorial Calculator is available for download in Related topics . Note that in order to completely understand the GUI code you should have some experience with creating Swing GUIs. Even without this prior knowledge, you should be able to discern many elements of the code from our prior discussion throughout this tutorial.

To get started, let's see what our GUI application looks like. Here's a screenshot of the GUI showing the result of calculating 100! (that is, 100 factorial).

The factorial engine: factor.py

Factorial is the class that supplies the factorial calculation engine. It consists of a sequence of code with additional explanation lines (identified by -- ) added.

-- import the needed modules
import sys
import exceptions

-- create the Factorial class, a general purpose factorial calculation engine
class Factorial:
    """A general purpose factorial calculation engine"""

-- define the constructor
    def __init__ (self):
        self.__listeners = []
        self.__cancelled = 0

-- allow other classes to register event listeners; 
---    used to track calculation progress
-- A "listener" is a function that takes an integer % argument
    def addListener (self, listener):
        if listener not in self.__listeners:
            self.__listeners.append(listener)

    def addListeners (self, listeners):
        for l in listeners:
            self.addListener(l)

    def removeListener (self, listener):
        self.__listeners.remove(listener)

    def removeListeners (self, listeners):
        for l in listeners:
            self.removeListener(l)

    def fireListeners (self, value):  # notify all listeners
        for func in self.__listeners:
            func(value)

-- allow others to cancel a long running calculation
    def cancel (self):
        self.__cancelled = 1

-- perform the factorial calculation; 
--     may take a long time (many minutes) for big numbers
    def calculate (self, value):
        if type(value) != type(0) or value < 0:
            raise ValueError,  \
               "only positive integers supported: " + str(value)

        self.__cancelled = 0
        result = 1L
        self.fireListeners(0)   # 0% done
        # calculate factorial -- may take quite a while
        if value > 1:           # need to do calculation
            last = 0
            # using iteration (vs. recursion) to increase performance
            # and eliminate any stack overflow possibility
            for x in xrange(1, value + 1):
                if self.__cancelled: break  # early abort requested
                result = result * x         # calc next value
                next = x * 100 / value
                if next != last:            # signal progress 
                    self.fireListeners(next)
                    last = next
        self.fireListeners(100)  # 100% done
        if self.__cancelled: result = -1
        return result

# test case
if __name__ == "__main__":
    print sys.argv[0], "running..."
    fac = Factorial()

    def doFac (value):
        try:
            print "For", value, "result =", fac.calculate(value)
        except ValueError, e: 
            print "Exception -", e

    doFac(-1)
    doFac(0)
    doFac(1)
    doFac(10)
    doFac(100)
    doFac(1000)

The GUI: fgui.py

Here you can see the set of classes that supplies the factorial GUI. The set consists of a sequence of code with additional explanation lines (identified by -- ) added.

-- import the needed modules
import sys
import string
from types import *

from java import lang
from java import awt
from java.awt import event as awtevent
from javax import swing

from factor import Factorial

-- PromptedValueLayout is a customized Java LayoutManager not discussed here 
--    but included with the resources
from com.ibm.articles import PromptedValueLayout as ValueLayout

-- support asynchronous processing
class LongRunningTask(lang.Thread):
    def __init__ (self, runner, param=None):
        self.__runner = runner   # function to run
        self.__param = param     # function parameter (if any)
        self.complete = 0
        self.running = 0

-- Java thread body
    def run (self):
        self.complete = 0; self.running = 1
        if self.__param is not None: 
            self.result = self.__runner(self.__param)
        else:
            self.result = self.__runner()
        self.complete = 1; self.running = 0

-- start a long running activity
def doAsync (func, param):
    LongRunningTask(func, param).start()

-- Swing GUI services must be called only on the AWT event thread,
class SwingNotifier(lang.Runnable):
    def __init__ (self, processor, param=None):
        self.__runner = processor  # function to do GUI updates
        self.__param = param       # function parameter (if any)

-- Java thread body
    def run (self):
        if self.__param is not None: self.__runner(self.__param)
        else:                        self.__runner()

    def execute (self):
        swing.SwingUtilities.invokeLater(self)
-- define and construct a GUI for factorial calculation
class FactorialGui(swing.JPanel):
    """Create and process the GUI."""

    def __init__ (self, engine):
        swing.JPanel.__init__(self)
        self.__engine = engine
        engine.addListener(self.update)
        self.createGui()

    def update (self, value):          # do on AWT thread
        SwingNotifier(self.updateProgress, value).execute()

    def updateProgress (self, value):  # display progress updates
        self.__progressBar.value = value

-- Calculate button press handler
    def doCalc (self, event):          # request a factorial
        self.__outputArea.text = ""
        ivalue = self.__inputField.text # get value to calculate
        value = -1
        try: value = int(ivalue)        # convert it
        except: pass
        if value < 0:                   # verify it
           self.__statusLabel.text = \
               "Cannot make into a positive integer value: " + ivalue
        else:
            self.__calcButton.enabled = 0
            self.__cancelButton.enabled = 1
            msg = "Calculating factorial of %i..." % value
            if value > 25000: msg += \ 
                 "; May take a very long time to complete!"
            self.__statusLabel.text = msg  # tell user we're busy
            doAsync(self.calcFac, value)   # do the calculation

-- main calculation worker
    def calcFac (self, value): 
        stime = lang.System.currentTimeMillis()
        fac = self.__engine.calculate(value)   # time calculation
        etime = lang.System.currentTimeMillis()
        svalue = ""; order = 0
        if fac >= 0:          # we have a result, not cancelled
            svalue = str(fac); order = len(svalue) - 1
            formatted = ""
            while len(svalue) > 100:  # wrap long numbers
                formatted += svalue[0:100] + '\n'
                svalue = svalue[100:]
            formatted += svalue
            svalue = formatted
        ftime = lang.System.currentTimeMillis()

        SwingNotifier(self.setResult, \
          (svalue, order, ftime - stime, etime - stime)).execute()

-- display the result
    def setResult (self, values):
        svalue, order, ttime, ftime = values
        self.__cancelButton.enabled = 0
        if len(svalue) > 0:
            self.__statusLabel.text = \
               "Setting result - Order: 10**%i" % order
            self.__outputArea.text = svalue
            self.__statusLabel.text = \
                "Total time: %ims, Calc time: %ims, Order: 10**%i" % \
                      (ttime, ftime, order)
        else:
            self.__statusLabel.text = "Cancelled"

        self.__calcButton.enabled = 1

-- Cancel button press handler
    def doCancel (self, event):       # request a cancel
        self.__cancelButton.enabled = 0
        self.__engine.cancel()

-- create (layout) the GUI
    def createGui (self):             # build the GUI
        self.layout = awt.BorderLayout()

        progB = self.__progressBar = \
            swing.JProgressBar(0, 100, stringPainted=1);

        inf = self.__inputField = swing.JTextField(5)
        inl = swing.JLabel("Calculate value of:", swing.JLabel.RIGHT)
        inl.labelFor = inf

        outf = self.__outputArea = swing.JTextArea()
        outl = swing.JLabel("Result:", swing.JLabel.RIGHT)
        outl.labelFor = outf

        calcb = self.__calcButton = \
            swing.JButton("Calculate", actionPerformed=self.doCalc,
                          enabled=1, mnemonic=awtevent.KeyEvent.VK_C)
        cancelb = self.__cancelButton = \
             swing.JButton("Cancel", actionPerformed=self.doCancel,
                          enabled=0, mnemonic=awtevent.KeyEvent.VK_L)

        vl = ValueLayout(5, 5)
        inp = swing.JPanel(vl)
        vl.setLayoutAlignmentX(inp, 0.2)
        inp.add(inl); inp.add(inf, inl)
        self.add(inp, awt.BorderLayout.NORTH)

        vl = ValueLayout(5, 5)
        outp = swing.JPanel(vl)
        vl.setLayoutAlignmentX(outp, 0.2)
        outp.add(outl); outp.add(swing.JScrollPane(outf), outl)

        xoutp = swing.JPanel(awt.BorderLayout())
        xoutp.add(progB, awt.BorderLayout.NORTH)
        xoutp.add(outp, awt.BorderLayout.CENTER)

        self.add(xoutp, awt.BorderLayout.CENTER)

        sp = swing.JPanel(awt.BorderLayout())

        bp = swing.JPanel()
        bp.add(calcb)
        bp.add(cancelb)
        sp.add(bp, awt.BorderLayout.NORTH)

        sl = self.__statusLabel = swing.JLabel(" ")
        sp.add(sl, awt.BorderLayout.SOUTH)
        self.add(sp, awt.BorderLayout.SOUTH)

-- main entry point; launches the GUI in a frame
if __name__ == "__main__":
    print sys.argv[0], "running..."
    frame = swing.JFrame("Factorial Calculator",
                defaultCloseOperation=swing.JFrame.EXIT_ON_CLOSE)
    cp = frame.contentPane
    cp.layout = awt.BorderLayout()
    cp.add( FactorialGui(Factorial()) )
    frame.size = 900, 500
    frame.visible = 1

Wrapping up

摘要

This completes the two-part "Introduction to Jython" tutorial. While much of the tutorial functions as an overview, I hope I have provided you with enough advanced discussion, code examples, and incentive to proceed into more hands-on learning, specifically by developing your own programs in Jython.

In my opinion, Jython does for the Java platform what Visual Basic does for Microsoft's .NET: It provides much easier access to a complex development and execution environment. While easy to use, Jython improves upon the Java language by incorporating features the Java language lacks (some of which are also available today in .NET languages such as C#) without sacrificing any of the Java platform's capability (unless you count compile-time-type checking or a small reduction in effective performance).

We've discussed many of Jython's enhancements in this tutorial -- including for each iteration, property methods accessible as attributes, collection literals, generic collections that hold basic types (such as integers), generic functions, first-class functions, overloadable operators, C-like printf formatting, functions as event handlers, and dynamic code execution. Some of these features are so compelling that they will be included in the next version of the Java platform (that is, 1.5). Of course, with Jython you don't have to wait -- you can begin using them today!

附录

Appendix A: Character codes for array types

The table below lists the character codes for Jython array types (see Java arrays from Jython ).

Character type code Corresponding Java type
'z' Boolean
'c' 烧焦
'b' byte
'h'
'i' 整型
'l'
'f' 浮动
'd'

Note: The above table is from www.jython.org .

Appendix B: Common overloaded operators and methods

The following are the operators that are commonly (additional operators can be) overloaded:

操作员 Function to override 注释)
x + y
x += y
+x
__add__(self, other)
__radd__ (self, other)
__iadd__(self, other)
__pos__ self)
Implements + operator
x - y
x -= y
-x
__sub__(self, other)
__rsub__(self, other)
__isub__(self, other)
__neg__(self)
Implements - operator
x * y
x *= y
__mul__(self, other)
__rmul__(self, other)
__imul__(self, other)
Implements * operator
x / y
x /= y
__div__(self, other)
__rdiv__(self, other)
__idiv__(self, other)
Implements / operator
x % y
x %= y
__mod__(self, other)
__rmod__(self, other)
__imod__(self, other)
Implements % operator
x & y
x &= y
__and__(self, other)
__rand__(self, other)
__iand__(self, other)
Implements & operator
x | ÿ
x |= y
__or__(self, other)
__ror__(self, other)
__ior__(self, other)
Implements | 算子
x ^ y
x ^= y
__xor__(self, other)
__rxor__(self, other)
__ixor__(self, other)
Implements ^ operator
~ x __invert__(self) Implements ~ operator
x << y
x <<= y
__lshift__(self, other)
__rlshift__(self, other)
__ilshift__(self, other)
Implements << operator
x >> y
x >>= y
__rshift__(self, other)
__ rrshift__(self, other)
__ irshift__(self, other)
Implements >> operator
x ** y
x **= y
__pow__(self, other)
__rpow__(self, other)
__ipow__(self, other)
Implements ** operator
divmod(x,y) __divmod__(self, other)
__rdivmod__(self, other)
Implements divmod()
x < y __lt__(self, other) Implements < operator. This should return the opposite value returned by __ge__.
x <= y __le__(self, other) Implements <= operator. This should return the opposite value returned by __gt__.
x > y __gt__(self, other) Implements > operator. This should return the opposite value returned by __le__.
x >= y __ge__(self, other) Implements >= operator. This should return the opposite value returned by __lt__.
x == y __eq__(self, other) Implements == operator. This should return the opposite value returned by __ne__.
x != y
x <> y
__ne__(self, other) Implements != operator. This should return the opposite value returned by __eq__.
cmp(x,y) __cmp__(self, other) Implements cmp() ; also used for relational tests if above specific overrides are not defined. This should return a < 0, 0 or > 0 value (say -1, 0 or 1).
X __nonzero__(self) Implements logical tests. This should return 0 or 1.
hash(x) __hash__(self) Implements hash() . Returns an integer value. Instances that are equal (that is, __eq__ returns true) should return the same __hash__ value (that is, (x == y) and (hash(x) == hash(y)) should be true. Similar to java.lang.Object.hashCode() .
绝对(x) __abs__(self) Implements abs()
int(x) __int__(self) Implements int()
long(x) __long__(self) Implements long()
float(x) __float__(self) Implements float()
complex(x) __complex__(self) Implements complex()
oct(x) __oct__(self) Implements oct()
hex(x) __hex__(self) Implements hex()
coerce(x,y) __coerce__(self, other) Implements coerce()
y = x.name __getattr__ (self, name) Implements attribute lookup
x.name = y __setattr__ (self, name) Implements attribute creation/update
del x.name __delattr__ (self, name) Implements attribute removal
y = c[i] __getitem_ (self, i) Implements item lookup
c[i] = y __setitem__ (self, i) Implements item creation/update
del c[i] __delitem__ (self, i) Implements item removal
x(arg, ...) __call__ (self, arg, ...) Implements the call operator
len(c) __len__ (self) Implements len()
x in c
x not in c
__contains__ (self, other) Implements in operator
class() __init__ (self, ...) Instance constructor; called when the class is created
del x __del__ (self) Instance destructor; called just before being deallocated
repr(x)
-- or --
`x`
__repr__(self) Implements repr() on this class
str(x) __str__(self) Implements str() on this class; Jython uses __repr__ if __str__ is not defined. str() is used like x.toString() in Java

Note: For the binary operators, the __xxx__ form is used when the left (or both) argument implements the function; the __ r xxx__ form is used only if the right argument implements the function and the left argument does not; the __ i xxx__ form is used to implement the augmented assignment ( x ?= y ) operation. See the Python Reference Manual for more details and overload-able functions.

Appendix C: Jython debugger commands

The debugger provides the following functions/features:

命令 Arguments 功能
h, help -- none -- List the available commands
w, where -- none -- Shows the current stack trace
d, down -- none -- Move down one stack frame
u, up -- none -- Move up one stack frame
b, break line# | function, condition_expr Set a breakpoint at a line number or function with an optional expression to evaluate - stop only if true
tbreak line# | function, condition_expr Set a breakpoint at a line number or function with an optional expression to evaluate - stop only if true; the breakpoint is automatically cleared when hit
cl, clear bpid... Clears all or listed breakpoints
使能 bpid... Enables breakpoints
禁用 bpid... Disabled breakpoints
忽视 bpid, count Sets the breakpoint ignore (auto-resume) count
健康)状况 bpid, condition_expr Sets the breakpoint condition expression
s, step -- none -- Steps over the next line, possibly into a function
n, next -- none -- Resume until the next line is reached
r, return -- none -- Resume until the current function returns
c, cont, continue -- none -- Resume execution
j, jump line# Set a new current line
l, list line#1, line#1 Lists source from line#1 to line#2, if omitted, then list the lines around the current line
a, args -- none -- Show the arguments of the current function
p, pp expr Evaluate the expression and print its result; pp formats the result
打印 expr Do the print statement, that is, - !print expr
别名 name, expr Create a named expression to simplify printing of repeated values
unalias 名称 Delete an alias
q, quit -- none -- End the debugging session
声明 Execute the Jython statement

Note: entering a blank line repeats the prior command.

Appendix D: Jython to/from Java type mapping

Jython uses these rules to map parameter types:

Java Parameter Types Allowed Python Types
烧焦 String (must have length 1)
Boolean Integer (true = nonzero)
byte, short, int, long 整数
float, double 浮动
java.lang.String, byte[], char[]
java.lang.Class Class or JavaClass
Foobar[] Array (must contain objects of class or subclass of Foobar)
java.lang.Object String->java.lang.String, all others unchanged
org.python.core.PyObject All unchanged
Foobar Instance --> Foobar (if Instance is subclass of Foobar); JavaInstance --> Foobar (if JavaInstance is instance of Foobar or subclass)

Jython uses these rules to map return value types:

Java Return Type Returned Python Type
烧焦 String (of length 1)
Boolean Integer (true = 1, false = 0)
byte, short, int, long 整数
float, double 浮动
java.lang.String
java.lang.Class JavaClass which represents given Java class
Foobar[] Array (containing objects of class or subclass of Foobar)
org.python.core.PyObject (or subclass) 不变的
Foobar JavaInstance which represents the Java Class Foobar

Note: the above two tables are from the www.jython.org site.

Appendix E: The sys module

The sys module has some important variables:

Variable 注释)
精氨酸 The arguments supplied to the main module. argv[0] is the program name, argv[1] is the first argument and so on
maxint
minint
Largest/smallest integer value
platform The version of Java Jython is running on
路径 The module search path
stdin
stdout
stderr
Standard input, output and error streams
模组 List of currently loaded modules

version_info
Jython version and details

The sys module has some important functions:

功能 注释)
exit(int) Exits the program
exc_info() Get information on the most recent exception

See the Python Library Reference for more information.

Appendix F: The os module

The os module has some important variables:

Variable 注释)
名称 Type of host
curdir String to represent the current directory
pardir String to represent the parent directory
九月 String to separate directories in a path
pathsep String to separate paths in a path set string
linesep String to separate text lines
环境 The current environment string

The sys module has some important functions:

功能 注释)
getcwd() Get the current directory
mkdir(path)
makedirs(path)
rmdir(path)
Create/delete a directory
remove(path)
-- or --
unlink(path)
Delete a file
listdir(path) List the files in a path
rename(path, new) Renames a file/directory to new
system(command) Run a shell command

See the Python Library Reference for more information.

Appendix G: The os.path module

The os.path module has some important functions:

功能 注释)
exists(path) True is path exists
abspath(path)
normpath(path)
normcase(path)
Returns the absolute form of the path
Returns the normalized form of the path
Returns the path in the normal case
basename(path)
dirname(path)
Returns the file part of path
Returns the directory part of path
commonprefix(list) Returns the longest common prefix of the paths in the list
gethome() Gets the home directory
getsize(path) Gets the size of the path file
isabs(path)
isfile(path)
isdir(path)
Tests to see if path is absolute
Tests to see if path is a file
Tests to see if path is a dir
samepath(path1, path2) True if path1 and path2 represent the same file
join(list) Joins the path elements in the list
split(path)
splitdrive(path)
splitext(path)
Returns (path, last_element)
Returns (drive, rest_of_path)
Returns (root, extension)

See the Python Library Reference for more information.

Appendix H: Regular expression control characters

The most useful Regular Expression special characters are:

Special Notation 注释)
Any character except those below Matches that character
Matches any character
^ Matches the start of the string
$ Matches the end of the string

??
Matches longest 0 or 1 of the proceeding
Matches shortest 0 or 1 of the proceeding
+
+?
Matches longest 1 or more of the proceeding
Matches shortest 1 or more of the proceeding
*
*?
Matches longest 0 or more of the proceeding
Matches shortest 0 or more of the proceeding
{m,n}
{m,n}?
Matches longest m to n of the proceeding
Matches shortest m to n of the proceeding
[...]
[^...]
Defines the set of enclosed characters
Defines the set of non-enclosed characters
...|... Matches a choice (or)
(...)
(?...)
Matches the sequence (or group) ...; groups are ordered from left to right with origin 1
Matches a sequence but does not define a group
(?P...)
(?P=name)
Matches a sequence (or group) ... giving it a name
Matches the sequence defined with the name
(?=...)
(?!...)
Matches ... but does not consume the test
Matches not ... but does not consume the test
\C Special characters:
\c literal escapes: .?*+&^$|()[]
\c function escapes: see below

See the Python Library Reference for more information.

Function escapes:

Function Escapes 注释)
\一个
\Z
Matches at start of line
Matches at end of line
\B
\b
Matches not at beginning or end of a word
Matches at beginning or end of a word
\ D
\d
Matches not any decimal digit (0..9)
Matches any decimal digit (0..9)
\ S
\s
Matches not any white space
Matches any white space
\W
\w
Matches not any alpha-numeric characters
Matches any alpha-numeric characters
\# Matches group #

Several options exist to modify how regular expression are processed. Options are bit flags and may be combined by OR-ing (|) them together. Some of the more useful options are:

选项 注释)
IGNORECASE
-- or --
一世
Match ignoring case
MULTILINE
-- or --
中号
Causes '^' and '$' to match internal line boundaries (vs. just the start and end of the string)
DOTALL
-- or --
小号
Causes '.' to match a newline

Appendix I: Generated factor.java

The following is the code generated by jythonc compiler for the factor.py file of The factorial engine: factor.py .

import org.python.core.*;

public class factor extends java.lang.Object {
     static String[] jpy$mainProperties =
         new String[] {"python.modules.builtin",
                       "exceptions:org.python.core.exceptions"};

     static String[] jpy$proxyProperties =
         new String[] {"python.modules.builtin",
                       "exceptions:org.python.core.exceptions",
                       "python.options.showJavaExceptions",
                       "true"};

     static String[] jpy$packages = new String[] {};

     public static class _PyInner extends PyFunctionTable
            implements PyRunnable {
         private static PyObject i$0;
         private static PyObject i$1;
         private static PyObject s$2;
         private static PyObject l$3;
         private static PyObject i$4;
         private static PyObject s$5;
         private static PyObject s$6;
         private static PyObject s$7;
         private static PyObject s$8;
         private static PyObject s$9;
         private static PyObject i$10;
         private static PyObject i$11;
         private static PyObject s$12;
         private static PyFunctionTable funcTable;
         private static PyCode c$0___init__;
         private static PyCode c$1_addListener;
         private static PyCode c$2_addListeners;
         private static PyCode c$3_removeListener;
         private static PyCode c$4_removeListeners;
         private static PyCode c$5_fireListeners;
         private static PyCode c$6_cancel;
         private static PyCode c$7_calculate;
         private static PyCode c$8_Factorial;
         private static PyCode c$9_doFac;
         private static PyCode c$10_main;
         private static void initConstants() {
             i$0 = Py.newInteger(0);
             i$1 = Py.newInteger(1);
             s$2 = Py.newString("only positive integers supported: ");
             l$3 = Py.newLong("1");
             i$4 = Py.newInteger(100);
             s$5 = Py.newString("__main__");
             s$6 = Py.newString("running...");
             s$7 = Py.newString("For");
             s$8 = Py.newString("result =");
             s$9 = Py.newString("Exception -");
             i$10 = Py.newInteger(10);
             i$11 = Py.newInteger(1000);
             s$12 = Py.newString("C:\\Articles\\factor.py");
             funcTable = new _PyInner();
             c$0___init__ = Py.newCode(1, new String[] {"self"},
                                       "C:\\Articles\\factor.py",
                                       "__init__", false, false,
                                       funcTable, 0,
                                       null, null, 0, 1);
             c$1_addListener = Py.newCode(2,
                                          new String[]
                                          {"self", "listener", "ll"},
                                          "C:\\Articles\\factor.py",
                                          "addListener", false,
                                          false, funcTable, 1,
                                          null, null, 0, 1);
             c$2_addListeners = Py.newCode(2,
                                          new String[]
                                          {"self", "listeners", "l"},
                                          "C:\\Articles\\factor.py",
                                          "addListeners", false,
                                          false, funcTable, 2,
                                          null, null, 0, 1);
             c$3_removeListener = Py.newCode(2,
                                          new String[]
                                          {"self", "listener", "ll"},
                                          "C:\\Articles\\factor.py",
                                          "removeListener", false,
                                          false, funcTable, 3,
                                          null, null, 0, 1);
             c$4_removeListeners = Py.newCode(2,
                                          new String[]
                                          {"self", "listeners", "l"},
                                          "C:\\Articles\\factor.py",
                                          "removeListeners", false,
                                          false, funcTable, 4,
                                           null, null, 0, 1);
             c$5_fireListeners = Py.newCode(2,
                                          new String[]
                                          {"self", "value", "func"},
                                          "C:\\Articles\\factor.py",
                                          "fireListeners", false,
                                          false, funcTable, 5,
                                          null, null, 0, 1);
             c$6_cancel = Py.newCode(1,
                                          new String[]
                                          {"self"},
                                          "C:\\Articles\\factor.py",
                                          "cancel", false,
                                          false, funcTable, 6,
                                          null, null, 0, 1);
             c$7_calculate = Py.newCode(2,
                                          new String[]
                                          {"self", "value", "next",
                                           "x", "last", "result"},
                                          "C:\\Articles\\factor.py",
                                          "calculate", false,
                                          false, funcTable, 7,
                                          null, null, 0, 1);
             c$8_Factorial = Py.newCode(0,
                                          new String[]
                                          {},
                                          "C:\\Articles\\factor.py",
                                          "Factorial", false,
                                          false, funcTable, 8,
                                          null, null, 0, 0);
             c$9_doFac = Py.newCode(1,
                                          new String[]
                                          {"value", "e"},
                                          "C:\\Articles\\factor.py",
                                          "doFac", false,
                                          false, funcTable, 9,
                                          null, null, 0, 1);
             c$10_main = Py.newCode(0,
                                          new String[] {},
                                          "C:\\Articles\\factor.py",
                                          "main", false,
                                          false, funcTable, 10,
                                          null, null, 0, 0);
         }


         public PyCode getMain() {
             if (c$10_main == null) _PyInner.initConstants();
             return c$10_main;
         }

         public PyObject call_function(int index, PyFrame frame) {
             switch (index){
                 case 0:
                 return _PyInner.__init__$1(frame);
                 case 1:
                 return _PyInner.addListener$2(frame);
                 case 2:
                 return _PyInner.addListeners$3(frame);
                 case 3:
                 return _PyInner.removeListener$4(frame);
                 case 4:
                 return _PyInner.removeListeners$5(frame);
                 case 5:
                 return _PyInner.fireListeners$6(frame);
                 case 6:
                 return _PyInner.cancel$7(frame);
                 case 7:
                 return _PyInner.calculate$8(frame);
                 case 8:
                 return _PyInner.Factorial$9(frame);
                 case 9:
                 return _PyInner.doFac$10(frame);
                 case 10:
                 return _PyInner.main$11(frame);
                 default:
                 return null;
             }
         }

         private static PyObject __init__$1(PyFrame frame) {
             frame.getlocal(0).__setattr__("_Factorial__listeners",
                            new PyList(new PyObject[] {}));
             frame.getlocal(0).__setattr__("_Factorial__cancelled", i$0);
             return Py.None;
         }

         private static PyObject addListener$2(PyFrame frame) {
             frame.setlocal(2,
                  frame.getlocal(0).__getattr__("_Factorial__listeners"));
             if (frame.getlocal(1)._notin(
                    frame.getlocal(2) ).__nonzero__()) {
                 frame.getlocal(2).invoke("append", frame.getlocal(1));
             }
             return Py.None;
         }

         private static PyObject addListeners$3(PyFrame frame) {
             // Temporary Variables
             int t$0$int;
             PyObject t$0$PyObject, t$1$PyObject;

             // Code
             t$0$int = 0;
             t$1$PyObject = frame.getlocal(1);
             while ((t$0$PyObject =
                    t$1$PyObject.__finditem__(t$0$int++)) != null) {
                 frame.setlocal(2, t$0$PyObject);
                 frame.getlocal(0).invoke("addListener",
                     frame.getlocal(2));
             }
             return Py.None;
         }
private static PyObject removeListener$4(PyFrame frame) {
             frame.setlocal(2,
    frame.getlocal(0).__getattr__("_Factorial__listeners"));
             frame.getlocal(2).invoke("remove", frame.getlocal(1));
             return Py.None;
         }

         private static PyObject removeListeners$5(PyFrame frame) {
             // Temporary Variables
             int t$0$int;
             PyObject t$0$PyObject, t$1$PyObject;

             // Code
             t$0$int = 0;
             t$1$PyObject = frame.getlocal(1);
             while ((t$0$PyObject =
     t$1$PyObject.__finditem__(t$0$int++)) != null) {
                 frame.setlocal(2, t$0$PyObject);
                 frame.getlocal(0).invoke("removeListener",
                        frame.getlocal(2));
             }
             return Py.None;
         }

         private static PyObject fireListeners$6(PyFrame frame) {
             // Temporary Variables
             int t$0$int;
             PyObject t$0$PyObject, t$1$PyObject;

             // Code
             t$0$int = 0;
             t$1$PyObject =
                frame.getlocal(0).__getattr__("_Factorial__listeners");
             while ((t$0$PyObject =
                     t$1$PyObject.__finditem__(t$0$int++)) != null) {
                 frame.setlocal(2, t$0$PyObject);
                 frame.getlocal(2).__call__(frame.getlocal(1));
             }
             return Py.None;
         }

         private static PyObject cancel$7(PyFrame frame) {
             frame.getlocal(0).__setattr__("_Factorial__cancelled", i$1);
             return Py.None;
         }

         private static PyObject calculate$8(PyFrame frame) {
             // Temporary Variables
             int t$0$int;
             PyObject t$0$PyObject, t$1$PyObject;

             // Code
             if (((t$0$PyObject = frame.getglobal("type").
                  __call__(frame.getlocal(1)).
                  _ne(frame.getglobal("types").
                  __getattr__("IntType"))).__nonzero__()
                ? t$0$PyObject
                : frame.getlocal(1)._lt(i$0)).__nonzero__()) {
                 throw Py.makeException(
                    frame.getglobal("ValueError"),
                    s$2._add(frame.getglobal("str").
                       __call__(frame.getlocal(1))));
             }
             frame.getlocal(0).__setattr__("_Factorial__cancelled", i$0);
             frame.setlocal(5, l$3);
             frame.getlocal(0).invoke("fireListeners", i$0);
             if (frame.getlocal(1)._le(i$1).__nonzero__()) {
                 frame.setlocal(5, l$3);
             }
             else {
                 frame.setlocal(4, i$0);
                 t$0$int = 0;
                 t$1$PyObject = frame.getglobal("range").
                   __call__(i$1,frame.getlocal(1)._add(i$1));
                 while ((t$0$PyObject = t$1$PyObject.
                           __finditem__(t$0$int++)) != null) {
                     frame.setlocal(3, t$0$PyObject);
                     if (frame.getlocal(0).
                         __getattr__("_Factorial__cancelled").__nonzero__()) {
                         break;
                     }
                     frame.setlocal(5,
                        frame.getlocal(5)._mul(frame.getlocal(3)));
                     frame.setlocal(2,
                        frame.getlocal(3)._mul(i$4)._div(frame.getlocal(1)));
                     if 
(frame.getlocal(2)._ne(frame.getlocal(4)).__nonzero__()) {
                         frame.getlocal(0).invoke("fireListeners",
                            frame.getlocal(2));
                         frame.setlocal(4, frame.getlocal(2));
                     }
                 }
             }
             frame.getlocal(0).invoke("fireListeners", i$4);
             if (frame.getlocal(0).
                 __getattr__("_Factorial__cancelled").__nonzero__()) {
                 frame.setlocal(5, i$1.__neg__());
             }
             return frame.getlocal(5);
         }

         private static PyObject Factorial$9(PyFrame frame) {
             frame.setlocal("__init__",
                 new PyFunction(frame.f_globals,
                                new PyObject[] {}, c$0___init__));
             frame.setlocal("addListener",
                 new PyFunction(frame.f_globals,
                                new PyObject[] {}, c$1_addListener));
             frame.setlocal("addListeners",
                 new PyFunction(frame.f_globals,
                                new PyObject[] {}, c$2_addListeners));
             frame.setlocal("removeListener",
                 new PyFunction(frame.f_globals,
                                new PyObject[] {}, c$3_removeListener));
             frame.setlocal("removeListeners",
                 new PyFunction(frame.f_globals,
                                new PyObject[] {}, c$4_removeListeners));
             frame.setlocal("fireListeners",
                new PyFunction(frame.f_globals,
                               new PyObject[] {}, c$5_fireListeners));
             frame.setlocal("cancel",
                new PyFunction(frame.f_globals,
                               new PyObject[] {}, c$6_cancel));
             frame.setlocal("calculate",
                new PyFunction(frame.f_globals,
                               new PyObject[] {}, c$7_calculate));
             return frame.getf_locals();
         }

         private static PyObject doFac$10(PyFrame frame) {
             // Temporary Variables
             PyException t$0$PyException;

             // Code
             try {
                 Py.printComma(s$7);
                 Py.printComma(frame.getlocal(0));
                 Py.printComma(s$8);
                 Py.println(frame.getglobal("fac").
                    invoke("calculate", frame.getlocal(0)));
             }
             catch (Throwable x$0) {
                 t$0$PyException = Py.setException(x$0, frame);
                 if (Py.matchException(t$0$PyException,
                                       frame.getglobal("ValueError"))) {
                     frame.setlocal(1, t$0$PyException.value);
                     Py.printComma(s$9);
                     Py.println(frame.getlocal(1));
                 }
                 else throw t$0$PyException;
             }
             return Py.None;
         }

         private static PyObject main$11(PyFrame frame) {
             frame.setglobal("__file__", s$12);

             frame.setlocal("sys",
                           org.python.core.imp.importOne("sys", frame));
             frame.setlocal("types",
                           org.python.core.imp.importOne("types", frame));
             frame.setlocal("exceptions",
                           org.python.core.imp.importOne("exceptions", frame));
             frame.setlocal("Factorial",
                           Py.makeClass("Factorial",
                                        new PyObject[] {}, 
c$8_Factorial, null));
             if (frame.getname("__name__")._eq(s$5).__nonzero__()) {
                 Py.printComma(frame.getname("sys").
                               __getattr__("argv").__getitem__(i$0));
                 Py.println(s$6);
                 frame.setlocal("fac",
                                frame.getname("Factorial").__call__());
                 frame.setlocal("doFac",
                                new PyFunction(frame.f_globals,
                                               new PyObject[] {}, c$9_doFac));
                 frame.getname("doFac").__call__(i$1.__neg__());
                 frame.getname("doFac").__call__(i$0);
                 frame.getname("doFac").__call__(i$1);
                 frame.getname("doFac").__call__(i$10);
                 frame.getname("doFac").__call__(i$4);
                 frame.getname("doFac").__call__(i$11);
             }
             return Py.None;
         }

     }
     public static void moduleDictInit(PyObject dict) {
         dict.__setitem__("__name__", new PyString("factor"));
         Py.runCode(new _PyInner().getMain(), dict, dict);
     }

     public static void main(String[] args) throws java.lang.Exception {
         String[] newargs = new String[args.length+1];
         newargs[0] = "factor";
         System.arraycopy(args, 0, newargs, 1, args.length);
         Py.runMain(factor._PyInner.class, newargs,
                    factor.jpy$packages,
                    factor.jpy$mainProperties, null,
                    new String[] {"factor"});
     }

}

Note: The above code has been reformatted for line length.

Appendix J: Formatting strings and values

Note that a simplified form of Appendix J originally appeared as multiple panels in Part 1 of this tutorial.

Jython strings support a special formating operation similar to C's printf , but using the modulo ("%") operator. 右边的项目集在字符串中匹配的%x位置处替换为左边的字符串。 设置值通常是单个值,值的元组或值的字典。

The general format of the format specification is

%{(key)}{flag}...{width}{.precision}x

这是格式项目的指南:

  • key :在提供的字典中查找的可选键
  • flag : Optional flags (reasonable combinations supported)
    • # : Display any special format prefix (for example, "0" for octal, "0x" for hex)
    • + : Display a "+" on positive numbers
    • blank : Display a leading space on positive numbers
    • - : Left (vs. right) justify the value in the width
    • 0 : Left pad with "0" (vs. spaces)
  • width :字段的最小宽度(对于较大的值将更长)
  • 精度 :任意小数点后的位数
  • x : Format code as described below

The format operator supports the following format characters:

Character(s) Result Format 注释)
%s, %r %s does str(x) , %r does repr(x)
%i, %d Integer Decimal Basically the same format
%o, %u, %x, %X Unsigned Value In octal, unsigned decimal, hexadecimal
%f, %F Floating Decimal Shows fraction after decimal point
%e, %E, %g, %G Exponential %g is %f unless the value is small; else %e
%c 字符 Must be a single character or integer
%% 字符 The % character

Note: more details on the structure and options of the format item can be found in the Python Library Reference ( Related topics ). Use of case in format characters (for example, X vs x causes the symbol to show in matching case.

例如

print "%s is %i %s %s than %s!" % ("John", 5, "years", "older", "Mark")

print "Name: %(last)s, %(first)s" % \
	{'first':"Barry", 'last':"Feigenbaum", 'age':18}

版画

John is 5 years older than Mark!
Name: Feigenbaum, Barry

Appendix K: Built-in functions

Note that Appendix K appeared in Part 1 of this tutorial.

Jython provides very useful built-in functions that can be used without any imports. The most commonly used ones are summarized below:

Syntax Use/Comment(s) Example(s)
绝对(x) Absolute value abs(-1) --> 1
apply(func, pargs {, kargs})
-- or --
func(*pargs {, **kargs})
Execute the function with the supplied positional arguments and optional keyword arguments apply(lambda x, y: x * y, (10, 20)) --> 200
callable(x) Tests to see if the object is callable (ie, is a function, class or implements __call__) callable(MyClass) --> 1
chr(x) Converts the integer (0 - 65535) to a 1-character string chr(9) --> "\t"
cmp(x, y) Compares x to y: returns: negative if x < y; 0 if x == y; positive if x > y cmp("Hello", "Goodbye") --> > 0
coerce(x, y) Returns the tuple of x and y coerced to a common type coerce(-1, 10.2) --> (-1.0, 10.2)
compile(text, name, kind) Compile the text string from the source name. Kind is: "exec", "eval" or "single"
x = 2
c = compile("x * 2",
             "", "eval")
eval(c) --> 4
complex(r, i) Create a complex number complex(1, 2) --> 1.0+2.0j
complex("1.0-0.1j") --> 1.0-0.1j
dir({namespace}) Returns a list of the keys in a namespace (local if omitted) dir() --> [n1, ..., nN]
vars({namespace}) Returns the namespace (local if omitted); do not change it vars() --> {n1:v1, ..., nN:vN}
divmod(x, y) Returns the tuple (x /y, x % y) divmod(100, 33) --> (3, 1)
eval(expr {, globals {, locals}}) Evaluate the expression in the supplied namespaces
myvalues = {'x':1, 'y':2}
eval("x + y", myvalues) --> 3
execfile(name {,globals {, locals}}) Read and execute the named file in the supplied namespaces execfile("myfile.py")
filter(func, list) Creates a list of items for which func returns true filter(lambda x: x > 0, [-1, 0, 1, -5, 10]) --> [1, 10]
float(x) Converts x to a float float(10) --> 10.0
float("10.3") --> 10.3
getattr(object, name {, default}) Gets the value of the object's attribute; if not defined return default (or an exception if no default) getattr(myObj, "size", 0) --> 0
setattr(object, name, value) Creates/sets the value of the object's attribute setattr(myObj, "size", 10)
hasattr(object, name) Test to see if the object has an attribute hasattr(myObj, "size") --> 0
globals() Returns the current global namespace dictionary {n1:v1, ..., nN:vN}
locals() Returns the current local namespace dictionary {n1:v1, ..., nN:vN}
hash(object) Returns the object's hash value. Similar to java.lang.Object.hashCode() hash(x) --> 10030939
hex(x) Returns a hex string of x hex(-2) --> "FFFFFFFE"
id(object) Returns a unique stable integer id for the object id(myObj) --> 39839888
input(prompt) Prompts and evaluates the supplied input expression; equivalent to eval(raw_input(prompt)) input("Enter expression:")
with "1 + 2" --> 3
raw_input(prompt) Prompts for and inputs a string raw_input("Enter value:")
with "1 + 2" --> "1 + 2"
int(x{, radix}) Converts to an integer; radix: 0, 2..36; 0 implies guess int(10.2) --> 10
int("10") --> 10
int("1ff", 16) --> 511
isinstance(object, class) Tests to see if object is an instance of class or a subclass of class; class may be a tuple of classes to test multiple types isinstance(myObj, MyObject) --> 0
isinstance(x, (Class1, Class2)) --> 1
issubclass(xclass, clsss) Tests to see if xclass is a sub-(or same) class of class; class may be a tuple of classes to test multiple types issubclass(MyObject, (Class1, Class2)) --> 0
len(x) Returns the length (number of items) in the sequence or map len("Hello") --> 5
list(seq) Converts the sequence into a list list((1, 2, 3)) --> [1,2,3]
list("Hello") --> ['H','e','l','l','o']
tuple(seq) Converts the sequence into a tuple tuple((1, 2, 3)) --> (1,2,3) tuple("Hello")--> ('H','e','l','l','o')
long(x {, radix}) Converts to a long integer; radix: 0, 2..36; 0 implies guess long(10) --> 10L
long("10000000000") -->
10000000000L
map(func, list, ...) Creates a new list from the results of applying func to each element of each list map(lambda x,y: x+y, [1,2],[3,4]) --> [4,6]
map(None, [1,2],[3,4]) --> [[1,3],[2,4]]
max(x) Returns the maximum value max(1,2,3) --> 3
max([1,2,3]) --> 3
min(x) Returns the minimum value min(1,2,3) --> 1
min([1,2,3]) --> 1
oct(x) Converts to an octal string oct(10) --> "012
oct(-1) --> "037777777777"
open(name, mode {, bufsize}) Returns an open file. Mode is:(r|w|a){+}{b} open("useful.dat", "wb", 2048)
ord(x) Returns the integer value of the character ord('\t') --> 9
pow(x,y)
pow(x,y,z)
Computes x ** y
Computes x ** y % z
pow(2,3) --> 8
range({start,} stop {, inc})
xrange({start,} stop {, inc})
Returns a sequence ranging from start to stop in steps of inc; start defaults to 0; inc defaults to 1. Use xrange for large sequences (say more than 20 items) range(10) --> [0,1,2,3,4,5,6,7,8,9]
range(9,-1,-1) --> [9,8,7,6,5,4,3,2,1,0]
reduce(func, list {, init}) Applies func to each pair of items in turn accumulating a result reduce(lambda x,y:x+y, [1,2,3,4],5) --> 15
reduce(lambda x,y:x&y, [1,0,1]) --> 0
reduce(None, [], 1) --> 1
repr(object)
-- or --
`object`
Convert to a string from which it can be recreated, if possible repr(10 * 2) --> "'20'"
repr('xxx') --> "'xxx'"
x = 10; `x` --> "10'"
round(x {, digits}) Rounds the number round(10.009, 2) --> 10.01
round(1.5) --> 2
str(object) Converts to human-friendly string str(10 * 2) --> "20"
str('xxx') --> 'xxx'
type(object) Returns the type (not the same as class) of the object. To get the class use object.__class__ . Module types has symbolic names for all Jython types x = "1"; type(x) is type('') --> 1
zip(seq, ...) Zips sequences together; results is only as long as the shortest input sequence zip([1,2,3],"abc") --> [(1,'a'),(2,'b'),(3,'c')]

See the Python Library Reference ( Related topics ) for more details.

Appendix L: Jython types summary

Note that Appendix L appeared in Part 1 of this tutorial.

Jython supports many object types. The module types defines symbols for these types. The function type gets the type of any object. The type value can be tested (see ). The table below summarizes the most often used types.

Type symbol Jython runtime type 注释)
ArrayType PyArray Any array object
BuiltinFunctionType PyReflectedFunction Any built-in function object
BuiltinMethodType PyMethod Any built-in method object
ClassType PyClass Any Jython class object
ComplexType PyComplex Any complex object
DictType
-- or --
DictionaryType
PyDictionary Any dictionary object
FileType PyFile Any file object
FloatType PyFloat Any float object
FunctionType PyFunction Any function object
InstanceType PyInstance Any class instance object
-- none -- PyJavaInstance Any Java class instance object
IntType PyInteger Any integer object
LambdaType PyFunction Any lambda function expression object
ListType PyList Any list object
LongType PyLong Any long object
MethodType PyMethod Any non-built-in method object
ModuleType PyModule Any module object
NoneType PyNone Any None (only one) object
StringType PyString Any ASCII string object
TracebackType PyTraceback Any exception traceback object
TupleType PyTuple Any tuple object
类型类型 PyJavaClass Any type object
UnboundMethodType PyMethod Any method (without a bound instancee) object
UnicodeType PyString Any Unicode string object
XRangeType PyXRange Any extended range object

Note: several types map to the same Java runtime type. For more information on types see the Python Library Reference ( Related topics ).


翻译自: https://www.ibm.com/developerworks/java/tutorials/j-jython2/j-jython2.html

你可能感兴趣的:(jython_Jython简介,第2部分:编程要点)