Screenshot CONTENTS Screenshot

Classes, Instances, and Inheritance

Java graphics chic01.gif This tutorial assumes its audience has previous Java knowledge, or that the reader is acquiring Java knowledge from additional sources. What this means is that object-oriented coding (OOP) requires no introduction. If you know Java, you know objects. The terms class, instance, encapsulation, polymorphism, and inheritance all permeate Java discussions so there is only need for brief mention here. This chapter begins with an overview of encapsulation, abstraction, and information hiding followed by the definition of Jython classes. This quick start due to previous OOP knowledge does not mean that Jython classes and instances are the same as Java's. Differences do exist, and using both Jython and Java classes within Jython creates a duality that you should keep in mind while reading on. This duality means references to a class's properties may be unique to Java or Jython so always consider the context in which the class occurs. Fortunately Jython does not alter the nature or behavior of Java classes, so confusion concerning context is unlikely. After describing how to define Jython classes and discussing Jython class attributes, the details concerning Jython's inheritance, method overloading, constructors, and destructors appear. To complete the introduction to Jython classes, this chapter concludes with a plethora of example Jython classes.

Encapsulation, Abstraction, and Information Hiding

This section is really about name mangling and electric fences, but let's start with a review of more traditional object terms. Encapsulation is the combining, or aggregation, of multiple entities to produce a new, often higher-order entity such as a class. A class encapsulates data and related functionality into a single object. A class also provides abstraction by organizing functionality in a way that simplifies the interface and hides the details of the implementation. The battle against complexity continues with information hiding—showing users only what they need to see in the name of simplicity. Java, among other languages, takes an additional step to enforce abstraction with attribute permissions modifiers like private and protected—the electric fence approach. Despite the immediate appeal electric fences have when facing software complexity, others contend that such strictness is unnecessary, that the electric fence should merely be warning signs that the adventurous continue past at their own risk. This analogy serves to contrast Java's strict approach with Jython's privacy mechanisms, which are quite open and contrary to those in Java. Programmers can see and change most everything in Jython classes. A Jython convention for method and variable names implies privacy, though. An attribute that begins with one underscore is internal to the class. This is only by convention, not de jure. You can call attributes beginning with an underscore with impunity, but convention dictates you do so at your own risk. Jython variables that begin with two underscores are one step closer to enforced privacy, but it is only privacy through obscurity. The obscurity referred to is name mangling. Jython mangles the names of Jython class and instance attributes that begin with two underscores to encourage programmers to respect their privacy. The actual mangling is the addition of an underscore and the class name to the beginning of the attribute's name. The variable __var within the class A becomes _A__var. Mangling is the end of the protection— there is no further enforcement. Attributes are accessible using this mangled name, as can be seen in this example:

>>> class A: ... __classVar = "A class variable designated as private" ... def __init__(self): ... self.__instVar = "An instance variable designated as private" ... def __privateMethod(self): ... print "This method is designated as private." ... >>> inst = A() 


>>> inst._A__classVar 'A class variable designated as private' >>> inst._A__instVar 'An instance variable designated as private' >>> inst._A__privateMethod() This method is designated as private. 


Jython, in other words, doesn't work so hard to protect programmers from themselves. The complete digest of Jython's privacy mechanisms amounts to one underscore for "don't use unless you're sure of what your are doing" and two underscores for "don't use unless you're really sure of what you are doing." Another naming convention is two preceding and trailing underscores. This convention designates special or magic attributes that have special meaning in Jython, such as the __doc__ attribute. Therefore, the use of variables with two leading and trailing underscores is unwise unless implementing predefined special attributes. More details of Jython's special class attributes appear in the following chapter.

Defining Jython Classes

Jython class definitions occur within modules, in the interactive interpreter, or in dynamically generated code.The syntax of a class definition follows:

"class" class_name[(bases)]: code block 


The name class is the statement that begins the definition. The class name is any legal Jython identifier. Following the class name is an optional list of base classes, within parenthesis. A colon designates the end of the class statement and the beginning of the associated code block. A near-empty Jython class looks like this:

>>> class emptyClass: ... """This is a near-empty Jython class""" ... 


Dissecting this empty class reinforces the essential parts of a class definition. The word class starts the class definition. The identifier for the class is emptyClass. This class is not a subclass of any other classes because there is no parenthesis and list after its identifier. As is always the rule in Jython, the code block obeys indention delimiting, beginning with the code block being one indention level in from the class statement. We also see that the class is not quite empty because it has a documentation string. Just like functions and modules, a literal string at the beginning of a class code block becomes that class's __doc__ attribute, or docstring in Python lingo. A class is a callable object, and calling a class returns an instance object. To call our example class, emptyClass, add empty parenthesis after its name; emptyClass does not have a constructor that requires a certain number of arguments, so an empty argument list suffices. To confirm the distinction between the class emptyClass and the instance object it returns, use the built-in function type() as is done here:

>>> c = emptyClass() >>> type(emptyClass) <jclass org.python.core.PyClass at 3838683> >>> type(c) <jclass org.python.core.PyInstance at 7833967> 


What good is an empty class? Not much in Java, but Jython allows arbitrary changes to a Jython class. The emptyClass example lacks attributes except for __doc__. However, dynamically assigning attributes to emptyClass or an instance of emptyClass is possible because of Jython's dynamic nature. This example demonstrates:

>>> emptyClass.z = 30 >>> c = emptyClass() >>> c.x = 10 >>> c.y = -20 >>> c.__doc__ = "This was a near-empty Jython class" >>> c.x 10 >>> c.y -20 >>> c.z 30 >>> c.__doc__ 'This was a near-empty Jython class' 


Such arbitrary additions to Java classes do not work:

>>> from java.applet import Applet >>> a = Applet() >>> dir(a) [] >>> a.a=10 Traceback (innermost last): File "<console>", line 1, in ? TypeError: can't set arbitrary attribute in java instance: a 


Jython Class and Instance Attributes

Although it is clear that calling a class returns an instance of that class, the clarity of Jython's class-instance relationship from then on is wanting. Both the class and the instance have attributes unique from the other (Python literature uses attributes like Java literature uses members.) An instance attribute is unique and separate from a class attribute of the same name. Java designates class members with the use of the static keyword, but Jython has no such keyword. Because Jython lacks explicit modifiers that designate whether an attribute is class specific or unique to an instance, the guidelines that determine this require delineation. The following lists pertain only to Jython classes. Using Java classes and instances within Jython does not change the behavior of Java's class and instance members. The guidelines to creating Jython class and instance attributes are as follows:

The guidelines to accessing class and instance attributes are as follows:

After reviewing the list, what seems to be missing? A Python programmer is tempted to answer "Nothing." A Java programmer, however, will inevitably answer "Class static methods." While numerous mechanisms to add this functionality have floated around, there is no standard, built-in support for class static methods in Jython classes. Despite recurrence of the idea, there is also no clamoring to add such support because module-level functions suffice. All instances of a class share class attributes. On the other hand, instance attributes are unique to each instance of a class. Consider the class myFiles, which contains a class attribute definition like this:

>>> class myFiles: ... path = "/home/rbill" 


Because the path is a class attribute, all instances of the class myFiles share this same path object. However, if an instance creates an instance attribute named path, it is not only unique from the class attribute of the same name, but is also unique from all other instances of the myFiles class. To confirm path is class static requires creating two instances, changing the path, and then checking the value of path in each instance:

>>> c1 = myFiles() >>> c2 = myFiles() >>> myFiles.path = "c:\\windows\\desktop" >>> c1.path "c:\\windows\\desktop" >>> c2.path "c:\\windows\\desktop" 


Confirming the uniqueness of instance variables requires three instances. Remember that assignment to an identifier that is qualified, or prefixed, with the instance name, creates an instance attribute. This is equally true outside of the class definition and is used here to example instance variables:

>>> class myFiles: ... path = "/home/rbill" ... >>> c1 = myFiles() >>> c2 = myFiles() >>> c3 = myFiles() >>> c2.path = "c:\\windows\\desktop" # creates a new instance attrib >>> c3.path = "/export/home/solaris" # creates a new instance attrib >>> >>> c1.path # class attrib '/home/rbill' >>> c2.path # instance attrib unique to c2 'c:\\windows\\desktop' >>> c3.path # instance attrib unique to c3 '/export/home/solaris' 


Defining instance methods in a Jython class is similar to writing a Jython function. Jython methods use the very flexible parameter scheme already described for Jython functions. Jython methods can use ordered arguments and keyword arguments, parameters can have default values, and you can allow for unknown numbers of parameters with the * and ** designations in the method signature.The difference centers on the instance reference. In Java, the variable this references the specific instance in which it is contained. this is assumed, or implicit in Java, but Jython does no such implicit name binding for the instance object. Instead, every method in a Jython class must specify an identifier for the instance object in the first slot of the method's parameter list. While this first slot is an arbitrary identifier, the word self has become standard practice. An instance method that creates and prints an instance variable looks like the following:

>>> class test: ... def imethod(self): ... self.message = "This is an instance variable" ... print self.message ... >>> t1 = test() # create the instance >>> t2 = test() # create a second instance for comparison >>> t1.imethod() This is an instance variable >>> >>> # To prove the "message" data is unique to only instance "t1"... >>> t1.message 'This is an instance variable' >>> t2.message # imethod not called- so t2.message is not defined Traceback (innermost last): File "<console>", line 1, in ? AttributeError: instance of 'test' has no attribute 'message' 


You'll notice that the method definition of imethod is the same as a function definition except that the added self parameter (or other suitable identifier) is required to meet the instance obligation. Within the class's code block, references to instance attributes must be qualified with self, there is no implied understanding of other attributes contained within the object as is the case in Java. Consider a class with two methods called methodA and methodB. Because self must be explicit in attribute lookups, any reference to methodA from within methodB must use self.methodA. The Calendar class below serves to demonstrate the self prefix in instance references:

>>> class Calendar: ... def setDay(self, day): ... self.day = day ... def setMonth(self, month): ... self.month = month ... def getDay(self): ... return self.day ... def getMonth(self): ... return self.month ... def getDayandMonth(self): ... return self.getDay() + " " + self.getMonth() ... 


Setting and retrieving the instance variables day and month both use the self prefix in the Calendar class. Note that the use of other instance methods, as is done in getDayandMonth, also requires the self prefix to qualify other instance methods. Methods have their own local namespace, just like functions, so only variables within the instance and outside the method's local namespace require the self prefix. An example follows:

>>> class test: ... def methA(self): ... data = 10 # This is local to methA ... self.data = 20 # this is a separate instance variable 


Class and instance attributes are stored in the object's dictionary, or __dict__ variable. This means that attribute B in class A is available through A.__dict__[B]. The built-in function vars() is designed to return the __dict__ attribute of objects and is useful in exploring objects.

Constructors

A constructor is a method that initializes an instance of a class. A constructor in Jython is a method named __init__ defined within a Jython class. This __init__ method's parameters look similar to any other method's parameters in that the first slot belongs to the instance object usually called self. A constructor may not return a value other than None. The return statement is allowed in a constructor and is useful in cases where a certain condition should return control before completing the entire __init__ block. If return appears, it must be simply return or returnNone. A Jython class with a constructor that creates some instance variables looks like this:

>>> class contact: ... def __init__(self): ... self.name = "" ... self.phone = "" ... 


The number of parameters defined in a constructor determines how many arguments appear when calling a class. If a constructor requires two parameters plus the self slot, two arguments must appear when calling that class. If a contact class required a name and phone number as constructor parameters, it would look like this:

>>> class contact: ... def __init__(self, name, phone): ... self.name = name ... self.phone = phone ... 


This contact class uses the constructor to initialize the name and phone variables to the name and phone constructor parameters. Creating an instance of this new contact class now requires two parameters and looks like this:

>>> c = contact("Someone's name", "555-555-1234") >>> # Or with keyword arguments >>> c = contact(phone="555-555-1234", name="Someone's name") 


Supplying default values makes constructor parameters optional. Java can have multiple constructors to implement differing parameters. Jython cannot, but it does allow for great flexibility with parameters, including default values in methods like the constructor. Optional constructor parameters look like this:

>>> class contact: ... def __init__(self, name="", phone=""): ... self.name = name ... self.phone = phone ... 


Now calling the contact class can take any one of the following forms:

>>> c = contact() >>>c = contact("Someone's name") >>>c = contact("Someone's name","555-555-1234") >>>c = contact(name ="Someone's name") >>>c = contact(phone ="555-555-1234") >>>c = contact(name="Someone's name", phone="555-555-1234") 


A common use for a constructor is establishing a database connection that stays connected for the life of the object. The following example contains a constructor that demonstrates establishing a database connection at the object's instantiation. Note that this example depends on the MySQL database and its associated Java driver, both of which are available from http://www.mysql.org/.

>>> import java >>> import org.gjt.mm.mysql.Driver >>> from java.sql import DriverManager >>> class DBAdapter: ... def __init__(self, dbname): ... conString = "jdbc:mysql://localhost/%s" %% dbname ... self.db = DriverManager.getConnection(conString, "", "") ... print "DB connection established" 


After the DBAdapter class is instantiated, any instance method can access the database connection through the instance variable self.db. The time-consuming connection process is therefore only incurred once per instance. Constructors often need to call superclass constructors. To do so, use the classname, followed by the __init__ method, and no matter what the parameters are, make the first parameter self. The syntax looks like this in Jython:

Superclass.__init__(self, otherArgs) 


A more specific example is sub-classing the java.net.Socket class. The Socket class in Java has no such method as __init__, but the same syntax still applies. Jython internals handle which constructor to call. The following example demonstrates sub-classing the Socket class. Note that this example assumes you have an active Internet connection.

>>> from java.net import Socket >>> class SocketWrapper(Socket): ... def __init__(self, host, port): ... Socket.__init__(self, host, port) ... >>> s = SocketWrapper("www.digisprings.com", 80) 


The syntax used to initialize a superclass is not restricted to just Java superclasses. Initializing a Jython superclass works the same way, and even makes more sense considering its constructor really is __init__.

Finalizer or Destructor

A finalizer or destructor is a method that if defined, is called when the object is collected by garbage collection. Jython uses Java's garbage collection (gc), so when a Jython object becomes unreachable, and memory needs trimming, the JVM gc thread may reclaim that object. There are two things to remember when using finalizers in Jython: First, they incur a performance penalty, and secondly, there is no way to tell when, or if, an object will be finalized. A Jython finalizer is an instance method named __del__. This method looks like this:

>>> class test: ... def __del__(self): ... pass # close something, or clean up something here ... 


The "Constructors" section demonstrated the creation of a database connection in a constructor, but to truly make the class complete, that connection should be closed in a finalizer or in some other method that is explicitly called. The following example demonstrates closing a database connection in the object finalizer, but there are some caveats in doing this that are described following the example:

>>> import java >>> import org.gjt.mm.mysql.Driver >>> from java.sql import DriverManager 


>>> class DBAdapter: ... def __init__(self, dbname): ... conString = "jdbc:mysql://192.168.1.77/%s" %% dbname ... self.db = DriverManager.getConnection(conString, "", "") ... print "DB connection established" ... def __del__(self): ... if not self.db.isClosed(): ... self.db.close() ... 


Java's garbage collection, the nature of database resources and database licenses often conflict with the above approach. Because the Java virtual machine, and thus Jython, provides no guarantees as to when, or even if, garbage collection collects an unused object, relying on finalizers is dangerous. If an app creates numerous objects with database connections that are closed in finalizers, any delays in collecting such objects waste limited database resources. This is most evident where database licenses restrict the number of connections, but it is always a concern. The preceding example clarifies finalizers, but is not a prudent example of managing database connections. More on databases, including more clever resource management appears in , "Server-Side Web Programming."

Inheritance

We've seen that the ability to set an arbitrary attribute is one difference between Java and Jython classes. The explicit use of the self variable is another difference between Jython and Java. Clues pointing to a third difference between Jython and Java appeared early in the section Defining Jython Classes. Note that the definition of a Jython class allows a list of base classes. The use of the word "list" should pique interest for those accustomed to Java's enforcement of single-inheritance. Single-inheritance means that a Java class can only inherit from a single base class. A Java class can implement multiple interfaces, but can only subclass a single Java class. Jython, on the other hand, allows multiple-inheritance but still must comply with Java's restrictions. This again introduces the Java-Python duality found in Jython. Jython's inheritance capacity depends on the type of superclass. Because Java enforces single inheritance, Jython may only inherit from a single Java class; however, because Python allows multiple inheritance, Jython may inherit from multiple Python (Jython) classes. This duality makes Jython unique. It is not fully like Python, C++, and other languages that allow multiple inheritance because the number of Java superclasses is restricted. Additionally, it is not fully like Java because it may inherit from multiple Jython classes. Despite being restricted to a single Java base class, a Jython class may multiply-inherit from a single Java class along with multiple Jython classes (and Java interfaces). What follows are details concerning inheriting from Jython classes, Java interfaces and Java classes.

Subclassing Jython Classes

A Jython class need not inherit from any but can inherit from one, two, or many Jython base classes. Defining base, or super, classes occurs in the parentheses following the class identifier in a class definition. If you wish to inherit from the Thread class within the threading module and inherit from the scheduler class within the sched module, you can use:

>>> from sched import scheduler >>> from threading import Thread >>> class threadedScheduler(scheduler, Thread): ... pass ... 


Inheriting from multiple classes allows you to use methods from either base class or override methods from either base class. There are two ways to use, or call, a method defined in a base class from within a descendant. One is using the base class name and method name in dotted notation with the self instance object as the first argument.

>>> class parentClass: ... def parentMethod(self): ... print "Parent method called" ... >>> class child(parentClass): ... def callSuper(self): ... parentClass.parentMethod(self) ... >>> c = child() >>> c.callSuper() Parent method called 


Explicitly calling a superclass with the current instance object as the first parameter as demonstrated just above has two purposes. First, this is how you initialize superclasses in Jython. Second, this allows you to call a superclass's method even if it is overridden in the current class. The following example demonstrate the latter with a revised child class:

>>> class parentClass: ... def parentMethod(self): ... print "Parent method called" ... >>> class child(parentClass): 


... def parentMethod(self): ... print "Overridden parent method" ... def callSuper(self): ... parentClass.parentMethod(self) ... >>> c = child() >>> c.callSuper() Parent method called 


The other way to call a method in a superclass is using the self prefix. To call method B in the superclass, use self.B() then allow the object attribute lookup mechanisms to locate the method. This assumes that method B does not exist in the child instance:

>>> class Super: ... def B(self): ... print "B found in superclass" ... >>> class A(Super): ... def callSuper(self): ... self.B() ... >>> test = A() >>> test.callSuper() B found in superclass 


Attribute lookup for those identifiers qualified with the self prefix begins in the current instance, then proceeds through superclasses according to the order they are listed in the class definition. Therefore, changing the order of superclasses may change which attribute is found (assuming multiple superclasses define the same attribute). An example of this follows:

>>> class SuperA: ... def A(self): ... print "Test method from SuperA" ... >>> class SuperB: ... def A(self): ... print "Test method from SuperB" ... >>> class C(SuperA, SuperB): ... def callSuper(self): ... self.A() ... >>> test = C() >>> test.callSuper() Test method from SuperA >>> >>> class C(SuperB, SuperA): ... def callSuper(self): ... self.A() ... >>> test = C() >>> test.callSuper() Test method from SuperB 


Subclassing Java Interfaces

In Java, you implement an interface rather than subclass it. However, there currently is no explicit interface equivalent in Jython, or Python, versions 2.1 and earlier. Interfaces, or protocols, are currently only implied in Jython and Python. This means that to implement a Java interface in Jython, you use the same syntax as if the interface were a base class. Just as Java can implement multiple interfaces, you can inherit from multiple Java interfaces. The combination of multiple Jython classes and multiple Java interfaces is also acceptable:

>>> from java.text import CharacterIterator >>> from java.io import Serializable >>> from java.io import DataInput >>> from threading import Thread >>> class test(CharacterIterator, Serializable, DataInput, Thread): ... pass ... >>> t = test() 


What Is a PEP?

A PEP is a Python Enhancement Proposal. PEPs document the design and development of Python, and thus Jython. Requests for new features appear in PEPs, and there are currently two interesting PEPs concerning interfaces. PEP number 245 describes an interface syntax for Python so that defining an interface similar to Java's interfaces would be native in Jython. More information on PEP 245 is available at http://www.python.org/peps/pep-0245.html. Another PEP concerns an "object adaptation" proposal and it assumes an object does not necessarily know which protocols it supports when written, but can reply to the question, "Do you support this protocol (interface)?" This would require the introduction of a new adapt function, __adapt__ method, and __conform__ method. The "adaptation" proposal is PEP number 246 and is located at http://www.python.org/peps/pep-0246.html.

Either of these proposals could affect the way Jython uses Java interfaces in the future; however, neither is accepted at this point. Look for information concerning this in Jython's, and Python's 2.2 releases.

More information on all of Python's PEPs is at http://python.sf.net/peps/.


Subclassing a Java Class

Because Java enforces single-inheritance, Jython classes are also restricted to at most one Java class as a base class. An attempt to inherit from more that one Java class raises an exception:

>>> from java.applet import Applet >>> from java.util import Vector >>> class a(Applet, Vector): ... pass ... Traceback (innermost last): File "<console>", line 1, in ? TypeError: no multiple inheritance for Java classes: java.util.Vector and java.applet.Applet 


A Jython class that inherits from a Java class can also inherit from interfaces and Jython classes however. A sneaky few will try to fake multiple inheritance by using a Java class and another Java class wrapped in a Jython class, but this does not work:

>>> from java.awt import Checkbox >>> from java.awt import Label >>> class labelWrapper(Label): ... pass ... >>> class labelCheckbox(Checkbox, labelWrapper): ... pass ... Traceback (innermost last): File "<console>", line 1, in ? TypeError: no multiple inheritance for Java classes: org.python.proxies.__main__$labelWrapper$0 and java.awt.Checkbox 


Multiple inheritance from a Java class and a Jython class works, but only applies if the Jython class does not inherit from a Java class as is the case with Jython's Thread class:

>>> from threading import Thread >>> from java.awt import Label >>> class threadedLabel(Label, Thread): ... pass ... >>> tl = threadedLabel() 


Listing 6.1 is a module that contains an example of a class that inherits from a Java class. A full dissection of this follows starting with imports, then the class definition and the two instance methods within the FileFilter class. This example is a Jython module that should be placed somewhere on the sys.path so that the discussion can continue by importing the filefilter module. The filefilter module imports the following items:

The FileFilter class in Listing 6.1 inherits from the Java class java.io.FilenameFilter so that a java.io.File class can use it to retrieve a filtered directory listing. The list is filtered according to which files return 1 when applied to the accept instance method. Of the two instance methods in Listing 6.1, addFilter allows the loading of regular expressions into an instance variable, but accept is the method required to satisfy the role as a FilenameFilter. The instance variable self.ffilter is a PyList that holds the compiled regular expressions. This instance variable is created when the first filter is added, and that is the reason for the if 'ffilter' not in vars(self).keys() condition. A similar condition appears in the accept method as part of an assert statement that ensures at least one regular expression is added before using the filter.

Listing 6.1 A File-Filtering Class that Uses a Java Base Class
# file: filefilter.py from java import io from os import path import re class FileFilter(io.FilenameFilter): def addFilter(self, ffilter): if 'ffilter' not in vars(self).keys(): self.ffilter = [] self.ffilter.append(re.compile(ffilter)) def accept(self, dir, name): assert 'ffilter' in vars(self).keys(),'No filters added' for p in self.ffilter: if not p.search(path.join(str(dir), name)): return 0 return 1 


To use this new Jython module and class in the interactive interpreter, ensure that it is in the sys.path, and then type:

>>> import filefilter >>> from java import io >>> ff = filefilter.FileFilter() >>> ff.addFilter(".*\.tar\.gz") >>> ff.addFilter("eiei") >>> # Change the following line to use a path specific to your platform >>> L = io.File("c:\\windows\\desktop").list(ff) >>> >>> # print the list of files found >>> for item in L: ... print item ... eieio-0_16.tar.gz 


Working with Java classes requires extra care. First, Java types require translation into Jython classes, and vice-versa, for method parameters and return values. Information about how Jython and Java types translate is available in , "Operators, Types, and Built-In Functions." Calling members of a Java superclass requires careful explanation. There are two syntaxes for calling an attribute in a base class. The first is the class name plus method in dotted syntax with self supplied as the first argument, as in the following:

>>> from java import util >>> class test(util.Vector): ... def addToSuper(self, objectToAdd): ... "Calling a java superclass looks like this:" ... util.Vector.addElement(self, objectToAdd) ... >>> t = test() >>> t.addToSuper("a string") >>> t.toString() '[a string]' 


The problem with this first syntax is that the Java superclass does not see the call as originating from a subclass. This syntax does work for any public method, and it is required when explicitly initializing Java superclasses, but it does not work for protected instance methods—use the second syntax for that. The second syntax is self.method. This self prefixed syntax ensures Java sees the call as originating in a subclass, which is required to access protected instance methods. Listing 6.2 demonstrates accessing members of a Java superclass using both syntaxes.

Listing 6.2 Calling Methods in a Java Superclass
# file: javabase.py import sys from java import util class cal(util.GregorianCalendar): def __init__(self): # This uses the "classname.method(self)" syntax # to initialize the superclass util.GregorianCalendar.__init__(self) def max(self): # This uses the "classname.method(self)" syntax return util.GregorianCalendar.getActualMaximum(self, 1) def min(self): # Another example of "classname.method(self)" syntax return util.GregorianCalendar.getActualMinimum(self, 1) def compute1(self): # This tries the "classname.method(self)" syntax. # This will not work because the method called is protected. try: util.GregorianCalendar.computeTime(self) return "Success" except AttributeError, e: print "compute1 failed.\n", e def compute2(self): # This uses the "self.method()" syntax so that the call appears # to originate from the base class. try: self.computeTime() return "success" except AttributeError, e: print "compute2 failed.", e Assuming that the above module is in the sys.path, you can test it with this: >>> import javabase >>> c = javabase.cal() >>> print "Trying max: ", c.max() Trying max: 292278994 >>> print "Trying min: ", c.min() Trying min: 1 >>> print "Trying compute1: ", c.compute1() Trying compute1: compute1 failed. class 'java.util.GregorianCalendar' has no attribute 'computeTime' None >>> print "Trying method compute2: ", c.compute2() Trying method compute2: success 


Java's protected and static modifiers are of special concern to Jython subclasses. Explaining this requires a quick peek under the hood of Jython. How does Jython access Java superclass class members? Some of the access is through a proxy object, which is the real subclass of the Java object, but some access is not through the proxy. Using self.add in a subclass of java.util.Vector (that does not override add) actually asks the proxy object to call the superclass method. The proxy, being the real subclass, has access to protected instance methods. However, the current implementation does not create proxy entries for class fields, or static members. What does this mean? It means that when a Jython subclass tries to access static methods or class fields, it does not occur from a real Java subclass. This makes protected fields, and protected static members the equivalent of private as far as the Jython subclass is concerned. Here's a quick list of what a Jython subclass does have access to:

Here is a list of what a normal Java subclass has access to, but a Jython subclass does not:

Such limitations are normally handled one of two ways. First, you can write Java classes to mediate access to required protected fields and protected static methods that you need. A section on trees at the end of this chapter demonstrates a Java class written to mediate inaccessible members. Second, there is the Jython registry setting python.security.respectJavaAccessibility. The Jython registry file is a file called registry in Jython's installation directory, or a file called .jython in a user's directory. The respectJavaAccessibility setting within this file can be true or false. If false, Jython gains access to protected and private members of Java classes (not just superclasses). As you might expect, there are additional implications for security and stability when circumventing accessibility restrictions this way. Also, requiring subsequent users of your work to also set respectJavaAccessibility to false might be troublesome. These issues require consideration when deciding to change the respectJavaAccessibility property. A final note on using Java superclasses involves superclass constructors. Explicitly calling a Java superclass constructor uses the classname.__init__(self) syntax.Without an explicit call, an empty superclass constructor is called after completion of the subclass's __init__ method.

Method Overloading

Java uses method overloading extensively. Method overloading allows, or requires, multiple methods with the same name for differing parameter lists. The differences in the parameter lists are the number of parameters and the parameter types. For example, the java implementation of Jython's xrange function requires three methods to implement:

public static PyObject xrange(int n) {
 return xrange(0,n,1); } public static PyObject xrange(int start, int stop) {
 return xrange(start,stop,1); } public static PyObject xrange(int start, int stop, int step) {
 return new PyXRange(start, stop, step); } 


While this is pervasive in Java, Jython does not provide for method overloading. The lack of method overloading certainly does not diminish Jython's expressiveness, but it does become an issue when working with Java classes. What happens when Jython code calls an overloaded Java method? It generally works as expected. Despite Jython's lack of method overloading, it does do a good job of using overloaded methods in Java classes. An example is this usage of the class java.lang.StringBuffer:

>>> import java >>> sb = java.lang.StringBuffer() >>> sb = java.lang.StringBuffer(10) >>> sb = java.lang.StringBuffer("Jython ") >>> sb.append(2.1) Jython 2.1 >>> sb.append("b") Jython 2.1b >>> sb.append("1") Jython 2.1b1 


The StringBuffer class has three different constructors, and the append method is also overloaded, but Jython employs all methods without trouble. Internally Jython identifies which Java method to call first by the number of parameters, then by types. Implementing overloaded Java methods does not mean overloading is possible in Jython classes, however. Because users can invoke overloaded Java methods from Jython, they assume overriding only a certain Java method in a Jython subclass should work. This is not true. When a Jython subclass overrides an overloaded Java method, it must handle all overloaded cases of that method. Jython does not employ method overloading by type signatures at all in this case. Even if it appears that the number of parameters should explicitly select a particular method, Jython remains non-selective. It's all or nothing when overriding an overloaded method. Listing 6.3 examines subclassing the java.awt.Dimension class. Listing 6.3 extends the Dimension class to make a similar class with boundaries. The interesting methods in Listing 6.3 are the constructor and setSize. The constructor establishes maximum sizes with optional parameter values, or a default of 100. The constructor also must initialize the superclass, which actually has three constructors. The subclass allows for each of the java.awt.Dimension constructors depending on what arguments it receives. Additionally, the setSize method of BoundaryBox overrides the superclass's methods of the same name. The superclass, Dimension, overloads the setSize method with these two type signatures:

void setSize(Dimension d) void setSize(double width, double height) 


Remember that overriding an overloaded method shadows all superclass methods of the same name. While specific usage of a class may mean some of these methods are insignificant to the situation, it is often the case that a new method within the subclass must handle multiple, or all superclass method signatures of the same name. In this case, it should allow for width, height values, or a Dimension instance in the setSize method. Listing 6.3 does allow for either of these arguments, but because of the limit testing, Listing 6.3 only need use one of the superclass's setSize methods.

Listing 6.3 Overriding Overloaded Java Methods
# file: boundarybox.py from java import awt import types import warnings as wrn # to shorten some lines class BoundaryBox(awt.Dimension): """BoundaryBox is a java.awt.Dimension subclass with max limits. The constructor accepts optional width and height values or a java.awt.Dimension instance, which provide max values""" def __init__(self, *args): if len(args)==2: # assume this is width, height self.maxWidth = args[0] self.maxHeight = args[1] awt.Dimension.__init__(self, args[0], args[1]) elif len(args)==1: # assume this is a Dimension instance self.maxWidth = args[0].getWidth() self.maxHeight = args[0].getHeight() awt.Dimension.__init__(self, args[0]) elif len(args)==0: self.maxWidth = 100 self.maxHeight = 100 awt.Dimension.__init__(self) def setSize(self, *dim): if len(dim) == 2: # args must be width, height w = self._testWidth(dim[0]) h = self._testHeight(dim[1]) elif len(dim) == 1 and isinstance(dim, awt.Dimension): # in case arg is a Dimension instance w = self._testWidth(dim.getWidth()) h = self._testheight(dim.getHeight()) else: assert 0, "'setSize accepts w, h or a Dimenstion inst" awt.Dimension.setSize(self, w, h) def _testWidth(self, w): if w > self.maxWidth: msg = "Width, %s, exceeds bounds. Changed to %s" print msg % (w, self.maxWidth) return self.maxWidth return w # width within bounds def _testHeight(self, h): if h > self.maxHeight: msg = "Height, %s, exceeds bounds. Changed to %s" print msg % (h, self.maxHeight) return self.maxHeight return h # height within bounds 


To test the BoundaryBox class, place the boundarybox.py file in the sys.path, and use the following:

>>> import boundarybox >>> bb = boundarybox.BoundaryBox(100, 200) >>> bb.setSize(50, 201) Height, 201, exceeds bounds. Changed to 200 >>> bb.setSize(101, 100) Width, 101, exceeds bounds. Changed to 100 >>> bb.width 100 >>> bb.height 100 


Sample Classes

To better understand Jython classes, it is best to examine demonstrations. This section provides demonstrations of not only Jython classes, but how they relate to similar Java classes.

Singletons

This example compares a Java implementation with similar functionality in Jython. The differences noted in the comparison helps clarify usage of Jython classes. When an app requires a single point of interaction with some specific object, Java programmers often create a class that restricts creation of more than one instance of itself. While there are different implementations of this, the most frequent seems to be combining a class field and class method to return the instance. Listing 6.4 shows a Java class containing an instance of itself in a class field. This class also has a class method, getInstance, which determines if an instance already exists before returning one. In this case, the class method returns a pre-existing instance if it already exists, but it is also common to raise an exception, or just return nothing.

Listing 6.4 Java Singleton
# file: Singleton.java public class Singleton {
 private static Singleton single=null; private Singleton() {} public static Singleton getInstance() {
 if (single==null) single = new Singleton(); return single; } //The methods which required a single point of access //go here. } 


This makes for an interesting comparison due to the lack of class methods and the inability to make a constructor private in Jython. How do you implement this in Jython? Using a non-constructor to return an instance is little value without a private modifier to restrict the actual constructor. A constructor cannot return a value, so it cannot choose a pre-existing instance to return. However, static class data attributes exist, and this can help test for an existing sequence. This only allows for a test, so this is most useful in an assertion or other expression that raises an exception when trying to create a second instance. This could look something like this:

# file: SimpleSingleton.py class Singleton: single = None def __init__(self): assert Singleton.single==None, "Only one instance allowed" Singleton.single = self def __del__(self): Singleton.single = None 


The usage would raise an AssertionError at the creation of a second instance:

>>> from SimpleSingleton import Singleton >>> s1 = Singleton() >>> s2 = Singleton() Traceback (innermost last): File "SimpleSingleton.py", line 11, in ? File "SimpleSingleton.py", line 4, in __init__ AssertionError: Only one instance allowed 


While raising an exception is sufficient in many situations, you may want the pre-existing instance. To more closely mimic the Java class in Listing 6.4, you need a substitute for class methods. Java's class-centric coding can dissuade some from module-level encapsulation and the use of functions, but you should be careful to not discount them. Combining a class and factory function within a module is often a solution, as it is here. Listing 6.5 shows this combination.

Listing 6.5 Function + Class = Singleton
# file: singleton.py class _Singleton: single = None def __init__(self): pass # put required methods here def __del__(self): _Singleton.single = None def Singleton(): if _Singleton.single == None: _Singleton.single = _Singleton() return _Singleton.single #add testing code to the module if __name__=='__main__': s1 = Singleton() s2 = Singleton() # set an instance data attribute in s1 s1.data = 4 # s2 should point to the same data value if it is really # the same instance print s2.data 


The result from running jython singleton.py is merely the integer 4, which confirms the same instance is shared by both the s1 and s2 identifiers in the preceding example.

File grep Utility

Listing 6.6 is a simple class that searches lines or files for a specified pattern. The constructor only caches a list of files in the specified directory. The findFiles method compares a pattern against this cached list (self.files) and returns a filtered list. The findLines reads each file line-by-line to return a list of lines containing the specified pattern. The two methods are most sensible used together by first limiting the file list with findFiles, then searching those files with findLines.

Listing 6.6 Searching Files with a Jython Class
# file: grep.py import os from os.path import isfile class directoryGrep: def __init__(self, directory): self.files = filter(isfile, [os.path.join(directory, x) for x in os.listdir(directory)]) def findLines(self, pattern, filelist=None): """Accepts pattern, returns lines that contain pattern Optional second argument a filelist to search""" if not filelist: filelist = self.files results = [] for file in filelist: fo = open(file) results += [x for x in fo.readlines() if x.find(pattern) != -1] fo.close() # explicit close of file object return results def findFiles(self, pattern): "Accepts pattern, returns filenames that contain pattern" return [x for x in self.files if x.find(pattern) != -1] # test if __name__=='__main__': g = directoryGrep("c:\\windows\\desktop") files = g.findFiles(".py") print g.findLines("java", files) 


The result from running jython grep.py on my machine is as follows:

['from java.lang import System\n', 'from java.lang import Runtime\n', 'from java.io Java graphics ccc.gifimport IOException\n', 'import java\n', 'from java.sql import DriverManager\n'] 


When reading files, Listing 6.6 explicitly closes the file objects it opens. Python programmers very frequently use the following phrase:

open(file).readlines() 


This creates and reads from an anonymous file object. This assumes that closing the file and releasing the resource occurs when garbage collection sees a need to collect it. Remember, Jython relies on Java garbage collection, so the actually closing of the file and releasing of the resource is delayed an unknown extent of time. The explicit closing of the object in Listing 6.6 avoids potential problems due to this latency.

HTTP Headers

HTTP headers consist of an actual request followed by a series of key-value pairs called headers and a blank line (\r\n\r\n), which terminates the request header. Listing 6.7 eases the manipulation of request data by parsing strings into data fields, and back to a string. Classes often help by mere containment and representation, meaning they group related data and can present that data in a useful way when needed. The containment in Listing 6.7 consists of two dictionaries, one containing request data, and the other containing headers. The interesting thing is that the dictionary containing the request data (method, URL, and HTTP version) is the instance dictionary, or self.__dict__. Listing 6.7 sets entries in this instance mapping as if it were a normal dictionary with self.__dict__.setdefault, and by using the instance attribute notation self.attribute = x syntax. Both approaches update self.__dict__. Representation, normally the toString method in a Java class, is the special method __repr__ in a Jython class. This method must return a string representation of an object if it exists, and when there is a need for a string representation of the object (like a print statement), this is the method called to provide it. Constructors, finalizers, and this representation method are all the special class methods discussed so far, but numerous special methods for customizing an objects behavior exist. Consider __repr__ just foreshadowing of a much larger set of special methods discussed in Chapter 7, "Advanced Classes."

Listing 6.7 Parsing HTTP Request Headers
# file: request.py import string import re class Request: """Class for working with request strings: The constructor optionally takes an http request string. e.g., req = Request("GET http://localhost/index.html HTTP/1.0")""" def __init__(self, request=None): "Parses a raw request string, if supplied. self.headers = {} if not request: request = "GET None HTTP/1.0" self.method, self.url, self.version = request.split()) self.host = self.path = self.file = "" match = re.match("http://(\S*?)(/.*)", self.url) if (match != None): self.host, self.path = match.groups() def setHeader(self, stringHdr): try: x,y = [x.strip() for x in stringHdr.split(":")] self.headers[x] = y except ValueError: raise SyntaxError("A header string must be " "in the format key : value") def __repr__(self): d = self.__dict__ # make a local copy for convenience request = " ".join([d['method'], d['url'], d['version']]) request += "\r\n" for key in self.headers.keys(): request += (key + ": " + self.headers[key] + "\r\n") request += "\r\n" return request # module testing code if (__name__=='__main__'): # Creating the instance can be without arguments... a = Request() # or with a raw request string like... a = Request("GET HTTP://freshmeat.net/index.html HTTP/1.0") # Headers are added/altered with "setHeader". # setHeader works with a header string as an argument... a.setHeader("Accept: image/jpeg, image/pjpeg, image/png, */*") a.setHeader("Proxy-Connection: Keep-Alive") a.setHeader("Accept-Encoding : gzip") #put it all together print a 


Output from running Jython request.py is:

GET HTTP://freshmeat.net/index.html HTTP/1.0 Accept: image/jpeg, image/pjpeg, image/png, */* Accept-Encoding: gzip Proxy-Connection: Keep-Alive 


Trees

Trees are common data structures that are excellent examples for demonstrating classes. Trees are collections of nodes and leaves, where a node contains other nodes and leaves, and a leaf terminates the branch (does not contain other nodes). The analogy more closely relates to family trees than the arborous alternative because of their top-down representation, and because the inter-relationship of nodes and leaves is often referred to as a parent-child relationship. Listing 6.8 defines two classes: leaf and node. The great thing about using trees is that nodes and leaves can have the same methods, so the interface for using a node or a leaf remains the same. This, combined with their inherent recursive structure makes for a clean, consistent, and widely applicable pattern. Hierarchical data such as taxonomies, company personnel, and filesystems are only a few examples of tree-like data. It's possible to apply the generic leaf and node classes in Listing 6.8 to a great number of similar tree-like structures. You only need to know three things about trees to create appropriate classes.

  1. A tree consists of nodes.

  2. Some nodes can have children.

  3. Leaves are nodes, but they are special because they cannot have children.

What does this mean for classes? It means there are specific expectations about what a class knows about itself and what functionality it provides. Questions a node object should be able to answer about itself are, Am I a leaf? Who's my parent? and Who are my children? The behavior expected from a non-leaf node object is the ability to add and remove children. The leaf class, despite not having children, also includes methods for adding and removing children, as well as answering,Who are my children? This ensures a consistent interface. These methods raise an exception, except in the case of the getChildren method, which returns a tuple so that it better matches node behavior. One additional requirement that is an implementation detail is that each object has a setParent method, which is required when adding objects to a node. Because a leaf node is just a node minus children, the leaf class subclasses node and overrides only those methods related to children.

Listing 6.8 Making Trees with Jython Classes
# file: trees.py class node: def __init__(self, name, value=None): self._children = [] self.name = name self.value = value self._leaf = 0 # Means this node can have children # These methods answer question the object must know about itself. def isLeaf(self): """returns answer to, "Am I a leaf?" """ return self._leaf def getParent(self): """returns answer to, "Who is my parent?" """ return self._parent def getChildren(self): """returns answer to, "Who are my children?" """ return tuple(self._children) # These methods supply required functionality of the object def addChild(self, node): node.setParent(self) self._children.append(node) def removeChild(self, node): try: self._children.remove(node) return 1 except ValueError: # in case that child doesn't exist return 0 # implementation detail def setParent(self, parent): self._parent = parent # A quick way to view the tree def dump(self, level=0): print "%s%s %s" %% (" "*level, self.name, self.value or "") for child in self.getChildren(): child.dump(level+1) def __repr__(self): return self.name class leaf(node): def __init__(self, name, value=None): node.__init__(self, name, value) self._leaf = 1 def addChild(self, node): raise ValueError, "Cannot add children to a leafNode" def removeChild(self, node): raise ValueError, "A leaf node has no children to delete." def getChildren(self): return () # returns empty tuple # Code to test these two classes if __name__=='__main__': root = node("root", "trees") evergreens = node("evergreens") evergreens.addChild(node("Picea", "Spruce")) deciduous = node("deciduous") deciduous.addChild(node("Acer", "Maple")) quercus = node("Quercus", "Oak") quercus.addChild(leaf("Alba", "White Oak")) quercus.addChild(leaf("Palustris", "Pin Oak")) quercus.addChild(leaf("Rubra", "Red Oak")) cdeciduous.addChild(quercus) root.addChild(evergreens) root.addChild(deciduous) children = root.getChildren() print children print quercus.getParent() print # add blank line print "Here is a dump of the entire tree structure:" root.dump() 


The results from running jython trees.py should look like:

(evergreens, deciduous) deciduous Here is a dump of the entire tree structure: root trees evergreens Picea Spruce deciduous Acer Maple Quercus Oak Alba White Oak Palustris Pin Oak Rubra Red Oak 


The Java implementation of a similar tree would no doubt be different, but how it would be different is interesting to look at. A Java tree would likely have an abstract class to ensure a consistent minimum for a legitimate node. Additionally, some instance variables would use the protected modifier. A potential abstract class in Java would look something like Listing 6.9.

Listing 6.9 An abstract Java Node Class
// file: Node.java import java.util.Vector; public abstract class Node {
 protected String name; protected Node parent = null; protected boolean leaf = false; public abstract Vector getChildren(); public abstract boolean addChild(Node n); public abstract boolean removeChild(Node n); public boolean isLeaf() {
 return leaf; } public String toString() {
 return name; } } 


This introduces some problems for the Jython tree classes. Namely, the protected fields leaf, parent, and name. A Jython subclass cannot access a protected Java field unless Jython's respectJavaAccessibility registry setting equals false. Let's assume that sidestepping access modifiers with the registry setting is unacceptable for whatever reason. The alternative is to write a Java class to mediate Jython's access to the abstract Node class. Listing 6.10 shows just such a Java adapter class.

Listing 6.10 A Java-to-Jython adapter Class
// file: JyNodeAdapter.java import Node; import java.util.*; public abstract class JyNodeAdapter extends Node {
 protected void setLeaf(boolean leaf) {
 this.leaf = leaf; } protected void setName(String nodeName) {
 name = nodeName; } public String getName() {
 return name; } public Node getParent() {
 return parent; } public void setParent(Node p) {
 parent = p; } public void dump() {
 this.dump(0); } public void dump(int level) {
 for (int i = 0; i < level; i++) {
 System.out.print(" "); } System.out.println(name + " " + this.value); Vector v = getChildren(); for (Enumeration e = v.elements(); e.hasMoreElements();) {
 JyNodeAdapter node = (JyNodeAdapter)e.nextElement(); node.dump(level + 1); } } } 


The only versions required to make the Jython tree classes is to add JyNodeAdapter as a superclass and alter attribute fetching and setting to use the appropriate set and get methods as designated in the Java superclasses. One additional change is altering the return value of getChildren to always be a Vector (empty Vector for the leaf) to comply with the protocol specified in the abstract Node class. Listing 6.11 shows the modified version of the Jython tree implementation with the appropriate modifications to use the Node and JyNodeAdapter base classes.

Listing 6.11 Jython Subclass of the JyNodeAdapter
# file: SubclassedTree.py import JyNodeAdapter from java.util import Vector class JyNode(JyNodeAdapter): def __init__(self, name, value=None): self.setName(name) self.value = value self._children = Vector() def getChildren(self): return self._children def addChild(self, c): c.setParent(self) self._children.add(c) return 1 def removeChild(self, c): self._children.removeElement(c) return 1 def __repr__(self): return self.toString() class leaf(JyNodeAdapter): def __init__(self, name, value=None): self.setName(name) self.value = value self.setLeaf(1) def addChild(self, node): raise ValueError, "Cannot add children to a leafNode" def removeChild(self, node): raise ValueError, "A leaf node has no children to delete." return Vector() # returns empty Vector def __repr__(self): return self.toString() if __name__=='__main__': root = JyNode("root", "trees") evergreens = JyNode("evergreens") evergreens.addChild(JyNode("Picea", "Spruce")) deciduous = JyNode("deciduous") deciduous.addChild(JyNode("Acer", "Maple")) quercus = JyNode("Quercus", "Oak") quercus.addChild(leaf("Alba", "White Oak")) quercus.addChild(leaf("Palustris", "Pin Oak")) quercus.addChild(leaf("Rubra", "Red Oak")) deciduous.addChild(quercus) root.addChild(evergreens) root.addChild(deciduous) children = root.getChildren() print children print quercus.getParent() print # add blank line print "Here is a dump of the entire tree structure:" root.dump() 


The results from running jython SubclassedTree.py should look like:

(evergreens, deciduous) deciduous Here is a dump of the entire tree structure: root trees evergreens Picea Spruce deciduous Acer Maple Quercus Oak Alba White Oak Palustris Pin Oak Rubra Red Oak 


Screenshot CONTENTS Screenshot
Comments