Screenshot CONTENTS Screenshot

Operators, Types, and Built-In Functions

Java graphics chic01.gif This chapter explains Jython's identifiers, data objects, operators and builtin functions. Nearly all items discussed in this chapter are available without user-supplied syntax—just like Java programmers get the classes in the java.lang package without any import statement. The exception is Java objects. Jython uses Java objects within Jython's syntax, but interacting with Java objects requires an import statement. Before beginning with objects, it is important to know which names (identifiers) are legal to bind objects to—; therefore, this chapter begins with the definition of legal Jython identifiers.

Identifiers

User-specified identifiers consist of letters, numbers, and the underscore, but they must always begin with a letter or the underscore. Spaces are not allowed, and case does matter. The length of the identifier doesn't matter. Identifiers cannot be reserved words, and Jython's list of reserved words include the following:

and

def

finally

in

print

as

del

for

is

raise

assert

elif

from

lambda

return

break

else

global

not

try

class

except

if

or

while

continue

exec

import

pass

Some examples of legal identifiers are as follows:

abcABC123 A1b2C3 _1a2 _a_1 


Some examples of illegal identifiers and the reasons why are as follows:

1abc # Identifiers cannot start with a number this variable # Spaces are not allowed cost$basis # Only letters, numbers and "_" are allowed 


Legal identifiers are not necessarily good identifiers. Despite the numerous reasons people choose to use Jython, or Python, it really seems that clarity is primary. It only makes sense to complement this with thoughtful choices of identifiers, and comments that clarify them where needed.

Jython Data Objects

Jython's data objects are derived from the Python language description, just as Jython itself is. The names ascribed to Python's types are integer, long, float, complex, string, tuple, list, and dictionary, among miscellaneous others. Jython, however, has no types in the traditional sense. This paradox is really only semantics. Type primitives are data descriptors that are not classes or instances. In Jython, however, all data is represented by Java classes from the org.python.core package. Therefore, Jython has no primitive types. The use of the word "type" in this tutorial is only a convenient way to refer to Jython's data classes. The use of classes for every data object is unique to Jython considering CPython types are not all objects. The names of the Java classes that represent the corresponding Python types are prefixed with "Py" so that they are PyInteger, PyLong, PyFloat, PyComplex, PyString, PyTuple, PyList, PyDictionary, and so on. Each class name and its associated Py* classes is used interchangeably throughout the tutorial (for example, tuple and PyTuple). The introduction to the Py* class such as PyFloat and PyList is really an implementation detail that is premature technically at this point in the tutorial, but the reason for their inclusion here is that these are the names you will get used to seeing when using the built-in function type(). Jython's data classes are dynamic—they are determined at runtime. They are also implied in that the value assigned to an identifier at runtime determines which data class is used as opposed to explicit type declarations. Jython code that binds names to objects looks like this:

>>>aString = "I'm a string" >>>aInteger = 5 >>>aLong = 2500000000L 


This code binds the PyString object to the name aString, the PyInteger object to the name aInteger, and the PyLong object to aLong. The string type is implied by the quotation marks, the integer type by the numeric literal 5, and the long type is designated by an integral number suffixed with an L. None of these variables' classes are determined by prefixing them with PyString or PyInteger, as it is done in Java. Explicit notation, such as the L suffix for PyLong objects, is rare in Jython. To confirm which type ("class") an objects is, you can use the built-in function type( ):

>>>type("I'm a string") <jclass org.python.core.PyString at 1777024> >>>S = "Another string" >>>type(S) <jclass org.python.core.PyString at 177024> >>>aInteger = 5 >>>type(aInteger) <jclass org.python.core.PyInteger at 7033304> >>>aLong = 2500000000L >>>type(aLong) <jclass org.python.core.PyLong at 871578> 


Note that the representation of numbers may differ from how you originally entered them—not the value, just the representation (for example, .1 = 0.1). There are a number of Py -prefixed classes in the org. python. core package. These classes have a plethora of public methods, but most of these methods are what is called special class methods, or they are methods for working with Py* classes from Java. An example of this is the toString() method. It is familiar and may be expected for Java programmers, but it is unique to the Java implementation of Python. Only those working in Java need to be aware of it. This section defines the basics of Jython's data objects, and leaves special class methods and Java specific methods for later chapters. The classes discussed here are not all that is represented by the Py* classes. Of the classes discussed, there are four numeric objects, three sequence objects, two mapping objects, and Jython's None object.

Numeric Objects

PyInteger, PyLong, PyFloat, and PyComplex are the classes that represent Jython's numeric objects. Variables with numeric types result from assignment to a numeric value of matching type. This means that if you bind a variable to a complex number, the PyComplex object is used.To clarify this, look at the definitions and examples of numeric objects in Table 2.1.

Table 2.1. Numeric Values

Class

Definition

Examples

PyInteger

A whole number limited in size to what can be represented with a Java primitive int type (32 bits or +/ –2147483647).

x = 28
x = -6

PyLong

A whole number followed by the letter "l" or "L". It is restricted in size only by available memory.

x = 2147483648L x = 6L

PyFloat

A floating-point number that is restricted in size to what can be represented with a Java primitive double type (64 bits).

x = 02.7182818284
x = 0.577216
x = 003.4E9

PyComplex

A complex number represented as the addition of two floating-point numbers. The first of which represents the real portion and the second is the imaginary. The letter "j" is appended to the second number to denote the imaginary portion.

x = 2.0+3.0
x = 9.32345+4j

Notice from Table 2.1 that values for the PyInteger class have a fixed range. An operation that causes a PyInteger object to exceed its maximum limit creates an overflow exception such as the following:

>>> int = 2147483647 >>> int += 1 Traceback (innermost last): File "<console>", line 1, in ? OverflowError: integer addition: 2147483647 + 1 


If an integral numeric object risks exceeding this limit, it should be made a PyLong by adding the L suffix. Despite the fact that the PyLong can be designated with either a capital L or lowercase l, the lowercase option is discouraged because of its similarity to the number 1. Out of the four numeric objects, only instances of the PyComplex class have a public instance method and instance variables that are commonly used from Jython. The instance variables are the real and imaginary portions of the complex number, accessed with x.real, and x.imag for the complex variable x. The instance method is .conjugate. The conjugate of a complex number is as follows:

conjugate(a + bi) = a - bi 


Examples of accessing the real and imaginary portions of the complex object, or invoking the conjugate instance method, use the same dot-notations as Java objects (instance.var). Calling the conjugate method would look like this:

>>>z = 1.5+2.0j >>>z.conjugate() (1.5-2.0j) >>>z + z.conjugate() (3+0j) 


Accessing the .real and .imag parts of a PyComplex instance would look like this:

>>>aComplexNumber = 1+4.5j >>>aComplexNumber.real 1.0 >>>aComplexNumber.imag 4.5 >>># Note that .real and .imag are PyFloat types >>>type(aComplexNumber.imag) <jclass org.python.core.PyFloat at 3581654> >>>type(aComplexNumber.real) <jclass org.python.core.PyFloat at 3581654> 


Another property of numerical objects is that they are all immutable—the value of a numeric object cannot be changed. Let's assume that you need to increment an integer object named x. To do so, you need to use an assignment operator, which instead of changing the value changes the object id. To look at an object's id, you can use the built-in function id().

>>>x = 10 # create our immutable variable >>>id(x) # get the id of x 2284055 >>>x = x + 1 # an assignment is required to add the 1 >>>id(x) # check x's new id 4456558 


The value of x appears incremented with the use of an assignment operator, but x is a different object because of the assignment, as noted by the difference in its id. In Boolean (true/false) expressions, all numeric objects are false when their value is equivalent to zero. Otherwise, they are true. This is demonstrated using Jython's if-else statement:

>>>if (0 or 0L or 0.0 or 0.0+0.0j): ... print "True" ...else: ... print "False" ... False 


These four classes are Jython's numeric objects, but they are not all of the numeric objects that can be used in Jython. Java's numeric classes can be used without modification in Jython. To do this, start with import java, then instantiate the class you need.

>>>import java >>>l = java.lang.Long(1000) >>>print l 1000 >>>l.floatValue() # invoke Java instance method 1000.0 


Sequence Objects

PyString, PyTuple, and PyList are the classes used for Jython sequences. These, being sequences, are ordered sets of data. The distinguishing features are the kind of data they hold, and their mutability. The PyString class holds only character data, whereas the PyTuple and PyList classes hold objects of any kind. Strings and tuples are immutable, meaning they cannot be changed, but lists are mutable. Unlike numeric objects, sequences have a length. The built-in function len() returns a sequence's length:

>>> len("This is a string sequence") 25 


Sequences share some common syntax, namely index and slice syntax. Although there is different syntax for creating the different sequences, they all use square brackets to reference elements within the set. First, examine the creation of each of the sequences:

>>>S = "abc" # This is a string >>>T = ("a", "b", "c") # This is a tuple >>>L = ["a", "b", "c"] # This is a list 


You can see they all have unique enclosure tokens—quotation marks, parentheses, and square brackets. However, if you want to access the second element of each sequence (the "b"), they all use the same syntax:

>>>S[1] 'b' >>>T[1] 'b' >>>L[1] 'b' 


The number within the square brackets is the index number, starting from 0, of an element within the sequence. Accessing a sequence element with an index like this returns the element at that index, counting from the start of the sequence (left). The index numbers can also be negative, which indicates the number of elements from the end of the sequence (right). This makes the index –1 the last element of a sequence, –2 the penultimate, and so on:

>>>S = "beadg" >>>S[-1] 'g' >>>S[-3] 'a' 


Sequences also share the same slice notation. A slice returns a subset of the original sequence. The colon, :, within the square braces is used to designate a slice. Numbers appearing on either side of this colon designate the range of the slice. Positive numbers (counted from the left), negative numbers (counted from the right), and the absence of numbers (designating respective endpoints) can be used to represent the range. So, a slice notation that looks like S[3:6] should be read as, "A slice of sequence S beginning at index 3 and continuing up to, but not including, index 6." The code for this slice looks like this:

>>>S = [1, 2, 3, 4, 5, 6, 7, 8, 9] >>>S[3:6] # slice from 3 up to, but not including 6 [4, 5, 6] 


A slice such as S [3: ] should be read as, "A slice of sequence S beginning at index 3 and continuing to its endpoint." The code for this slice looks like this:

>>>S = [1, 2, 3, 4, 5, 6, 7, 8, 9] >>>S[3:] [4, 5, 6, 7, 8, 9] >>> >>># if we invert the slice numbers... >>>S[:3] [1, 2, 3] 


A slice such as S [4:-2 ] should be read as, "A slice of sequence S beginning at index 3 and continuing to, but not including, its second index from the end." The code for this slice looks like this:

>>>S = [1, 2, 3, 4, 5, 6, 7, 8, 9] >>>S[4:-2] [5, 6, 7] >>> >>># negative number can be on the left also... >>>S[-4:-1] [6, 7, 8] 


Jython sequences also support a third integer in the slice syntax to represent step. This third integer is separated by a second colon within the square brackets, and it means a slice that looks like S [2:8:3 ] should be read as, "A slice of sequence S beginning at index 2 and including every third index until reaching index 8." Adding this third number lets you have slices like this:

>>> S = 'zahbexlwlvo2 fwzo4rslmd' >>> S[2::2] # this slices from index 2 to the endpoint, steping by 2 'hello world' >>> >>> L = [1,2,3,4,5,6,7,8,9] >>> L[-1:3:-1] # last index to third index, indexes step by -1 [9, 8, 7, 6, 5] 


Of the sequence classes, two are immutable— PyString and PyTuple. Listing 2.1 demonstrates mutability and the exception that is raised when you try to change an immutable type (tuple or string). In addition, a PyList object is created and altered in Listing 2.1 to demonstrate its mutability.

Listing 2.1 Examples of Sequence Objects
>>> S = "This is a string" # Make a PyString instance >>> type(S) # Confirm object type <jclass org.python.core.PyString at 8057966> >>> S[2] = "u" # Try to change the string Traceback (innermost last): File "<console>", line 1, in ? TypeError: can't assign to immutable object >>> >>> T = (1, 2.1, "string") # make a PyTuple with varied data >>> type(T) # Confirm object type <jclass org.python.core.PyTuple at 4573025> >>> T[2] = "new string" # Try to change the tuple Traceback (innermost last): File "<console>", line 1, in ? TypeError: can't assign to immutable object >>> >>> L = [1, 2.1, "string"] # Make a List with varied data >>> type(L) # Confirm object type <jclass org.python.core.PyList at 5117945> >>> L[2] = "new string" # Try to change the list >>>L[2] 'new string' 


In Boolean expressions, empty sequences evaluate to false. All other sequences evaluate to true. Sequences are more involved than the numeric objects, and each require their own section. The following three sections detail the properties of Jython's sequences. Each section introduces the syntax of the object, properties of the object, and methods associated with it.

PyString—The String Object

Jython's string class inherits Java's string properties in that they are constructed with two-byte characters based on the Unicode 2.0 standard. This is the only string type in Jython, departing from CPython where there are 8-bit and 16-bit string types with Unicode 3.0 characters. The CPython implementation has a string syntax where the letter u prefixes a Unicode string. Jython supports this syntax for compatibility, but the only changes to the string is in the interpretation of the special characters \u and \N. The string type, or instances of the PyString class, can be created by assigning a variable to a string literal. String literals are written with matching quotation marks. Either matching single-quotes ('), double-quotes ("), or the Jython convention of triple-quotes (""" or ''') works. The different marks allow embedding of other quotations such as the following:

"single-quotes ' in double-quotes" 'double-quotes " in single-quotes' """Triple quotes let you use "anything" inside except the matching triple quote, and let you span multiple lines""" '''This is also a triple quoted string just in case you need """ inside.''' 


Concatenation of string literals is an implied operation in Jython. Leaving white space between string literals concatenates them.

>>>print "Adding " 'strings ' 'together is ' "this simple." Adding string together is this simple. 


This is a convenient way to protect different quotation marks within a string, such as the following:

>>>print "I'm able to " 'mix "different" quotes this way.' I'm able to mix "different" quotes this way. 


Note that this only works with string literals. You cannot join a string literal with the value of an object. The concatenation operator + is required for that and is discussed later in this chapter. The following code demonstrates how attempting to use implied concatenation with non-string literals raises an exception:

>>>S = "String value held by object 's' " >>>print "String literal " S Traceback (innermost last): (no code object) at line 0 File "<console>", line 1 "literal" S ^ SyntaxError: invalid syntax 


There is an additional quotation convention designed to allow the string representation of data. This is reverse quotes. Results of expressions contained in reverse quotes are converted to a string representation of that data. The following code shows a PyInteger object and an integer literal within reverse quotes as an expression. Notice that the results of the expression is what is converted to a string, not the literal contents of the reverse quotes:

>>> n = 5 >>> s = `n + 2` >>> s '7' >>> type(s) <jclass org.python.core.PyString at 5471111> 


Reverse quotes do the same as the repr() function. The repr() function returns a string representation of data that is useful in reconstructing that data. This differs from the built-in str() method, which returns a string description of an object. Often times repr( object)==str( object), but there is no guarantee of this equality because these two functions have different objectives. This is revisited when discussing Jython objects and their special __str_ _ and _ _repr_ _ methods. PyString instances are created when binding a literal string value to a name like this:

>>>S = "A string" >>>type(S) <jclass org.python.core.PyString at 177024> 


Objects of type PyString support a number of methods. These methods are called with the Java-like dot notation object.method. The split method, for example, returns a list of sub-strings designated by a delimiter:

>>>S = "1,2,3,4,5" >>>S.split(",") ["1", "2", "3", "4", "5"] 


If no delimiter is specified, it splits on whitespace:

>>>S = "A string with spaces." >>>S.split() # notice, no delimiter specified ["A", "string", "with", "spaces."] 


String processing is one of Jython's strengths as evidenced by how rich the PyString class is with methods. A list of PyString methods is given in Table 2.2. A very important characteristic of sting methods is that they always return a copy of the string and never modify the string in place.

Table 2.2. PyString Methods

Method

Description

capitalize

s.capitalize( ) returns string matching the value of s except that the first character is capitalized:

>>>s="monday"
>>>s.capitalize()
Monday

center

s.center(width) returns the value of s centered within a string of specified width. The width represents a number of characters total desired in the returned string, and the value of s is padding with spaces to satisfy that width:

>>> s = "Title"
>>> s.center(40)
' Title '

count

s.count(substring [,start [, end]]) returns an integer representing the number of times a substring was found in the string value of s. The start and end parameters are optional and define a slice of the string to search in:

>>> s = "BacBb is the music-cryptic spelling of Java graphics ccc.gifBach. "
>>> s.count("c")
4
>>> s.count("c", 18)
3
>>> s.count("c", 18, 28)
2

encode

s.encode([encoding] [, error-handling]) returns the string value of s as a string with the character encoding specified or the default character encoding if not specified.The error-handling parameter represents how the encoding conversion process should handle errors. Error-handling can be set to strict, ignore, or replace:

>>> s = "René Descartes"
>>> s.encode("iso8859_9", "replace")
'Ren? Descartes' # note the replaced character Java graphics ccc.gif"?".

endswith

s.endswith(suffix[, start[, end]]) returns 1 if s ends with suffix, 0 otherwise.The optional start and end parameters represent the slice of the string to be considered when checking:

>>>s = "jython.jar"
>>>s.endswith(".jar")
1
>>>s.endswith("n", 5, 6)
1

expandtabs

s.expandtabs([tabsize]) returns the string with tab characters replaced with the number of spaces designated in tabsize, or 8 if no tabsize is given. A tab character is represented in a string as \t.

>>>s = "\tA tab-indented line"
>>>s.expandtabs(4)
' A tab-indented line'

find

s.find(substring [,start [,end]]) returns the index of the first occurance of substring in the string s. The start and end indexes are optional and restrict the search to within those bounds when supplied. A value of -1 is returned if the substring is not found.

>>>s = "abcdedcba"
>>>s.find("c")
2
>>>s.find("c", 5)
6

index

s.index(substring [,start [,end]]) is the same as find, except a ValueError exception is raised if the substring is not found.

isalnum

s.isalnum() returns 1 or 0 depending on whether the string value of s is all alphanumeric:

>>>s = "123abc"
>>>s.isalnum()
1
>>>s = "1.2.3.a.b.c"
>>>s.isalnum()
0

isalpha

s.isalpha() is the same as isalnum except that the string must be all characters before this method returns 1.

isdigit

s.isdigit() is the same as isalnum except that the string must be all numbers before this method returns 1.

islower

s.islower() returns 1 if there is at least one alpha character in the string and all the alpha characters are lowercased. If there are no alpha characters in the string or one of them is uppercased, it returns 0.

isspace

s.isspace() tests if the string is all whitespace and returns 1 if it is. If the string has non-whitespace characters, it returns 0.

istitle

"Title casing" is where the first letter of each word is capitalized and no non-first characters are capitalized. s.istitle() returns 1 if the string fits this convention.

>>>s = "Jython For Java Programmers"
>>>s.istitle()
1

isupper

s.isupper() returns 1 if all characters in the string are uppercased. It returns 0 if there is a lowercased character or if there are no alpha characters in the string.

join

s.join(sequence) joins a list, tuple, java.util. Vector, or any other sequence with the string value s as the separator.

>>>s = ", and "
>>>s.join(["This", "that", "the other thing"])
This, and that, and the other thing

ljust

s.ljust(width) pads the right side of the string with spaces to make a string of the specified width.

lower

s.lower() returns a copy of the string with all alpha characters made lowercase.

lstrip

s.lstrip(width) pads the left side of the string with spaces to make a string of the specified width.

replace

s.replace(old, new [, maxsplits]) returns a copy of the string with each "old" string replaced with the "new" string. There is an optional parameter, maxsplits, that should be a numeric value designating the maximum number of times the old string should be replaced. So, s.replace("this", "that", 5) would return a string with only the first five instances of "this" being replaced with "that."

rfind

s.rfind(substing [, start [, end]]) is the same as find except that it returns the highest index in string s where the substring is found, or the rightmost occurrence of the substring.

rindex

s.rindex(substring [,start [,end]]) is the same as rfind except a ValueError exception is raised if the substring is not found.

rjust

s.rjust(width) pads the left side of the string with spaces to make a string of the specified width.

rstrip

s.rstrip() returns the string with all trailing whitespace removed.

split

s.split([separator [, maxsplits]]) returns a list containing the string subdivisions of s divided by the provided separator, or by whitespace is no separator is provided. The maxsplits parameter, if provided, limits the number of splits performed, counting from the left, so that the last string in the list contains all that remains.

splitlines

s.splitlines([keepends]) returns a list of strings created by dividing s at each newline character it contains. The newline characters are not preserved unless the optional keepends paramaeter evaluates to true.

startswith

s.startswith(prefix [,start [,end]]) compares prefix to the beginning of the entire string, or to that portion of the string designated by the optional start and end parameters. If the prefix matches the beginning of the string it is compared against, it returns 1; otherwise it returns 0.

strip

s.strip() returns a copy of the string s with leading and trailing whitespace removed.

swapcase

s.swapcase() returns a copy of the string s with the capitalization of alpha characters inverted. Those that are lowercased are capitalized and vice-versa.

title

s.title() returns a titlecased copy of s. Titlecasing is where the first letter of each word is capitalized, whereas other letters are not.

translate

s.translate(table [,deletechars]) returns a translated copy of s. A translation can involve two things: remapping of characters (denoted by table) and a list of characters to delete (denoted by deletechars). The characters you want deleted are included in a string as an optional parameter, so to delete a, b, and C, use the following:

>>>s.translate(table, "abC")
 

The translation table is a 256-character string usually made with the string module's maketrans method. Importing and using modules is a bit premature here, but this is fairly intuitive:

>>>import string # this loads the string module
>>>table = string.maketrans("abc", "def")
>>>s = "abcdefg"
>>>s.translate(table, "g") # translate "abc" and Java graphics ccc.gifdelete "g"
'defdef'

upper

s.upper() returns a copy of string s with all alpha characters uppercased.

The variable s is used to represent the PyString instance.

PyTuple

The PyTuple class is an immutable sequence that can contain references to any type of object. There can sometimes be confusion over the fact that a tuple is immutable but can contain references to mutable objects. If its contents change, how can a tuple be immutable? This works because tuples contain references to objects—the id of the object. When a mutable object's value is changed, its id remains constant; thus, the tuple itself remains immutable. The syntax for a tuple is odd in that a comma-separated list evaluates to a tuple, but a tuple is represented by parentheses (). This means you can create a tuple with a comma-separated list within parentheses, or with a comma-separated list, or with empty parentheses for an empty tuple.

>>>t = (1,2,3) >>>type(t) <jclass org.python.core.PyTuple at 6879429> >>>t = 1,2,3 >>>type(t) <jclass org.python.core.PyTuple at 6879429> >>> type((1,2,3)) <jclass org.python.core.PyTuple at 6879329> >>>myTuple = (1, "string", 11.5) # tuples can contain any object type 


Constructing a single-element tuple still requires a comma:

>>> t1 = ("element one",) >>> t2 = "element one", >>> type(t1) <jclass org.python.core.PyTuple at 4229391> >>> type(t2) <jclass org.python.core.PyTuple at 4229391> >>> print t1 ('element one',) >>> print t2 ('element one',) 


Now, try to change the tuple to confirm it is immutable:

>>> T = ("string", 1, 2.4) >>> T[0]="another string" Traceback (innermost last): File "<console>", line 1, in ? TypeError: can't assign to immutable object 


In contrast to the PyString object, the PyTuple object has no associated methods.

PyList

PyList is similar to PyTuple, but it is mutable. The values can be changed. This makes PyList unique among the sequence classes. A list is denoted by enclosing comma-separated objects in square brackets [1,2,3], or just the square brackets to create an empty list []. The objects contained in a list can be any objects. Making a list that contained various objects, such as an integer, string, float, and complex, would look like the following:

>>>myList = [1,"a string", 2.4 , 3.0+4j] >>>type(myList) <jclass org.python.core.PyList at 250438> 


Objects of type PyList have nine associated methods. These methods are described in Table 2.3

Table 2.3. PyList Methods

Method

Description

append

L.append( object) adds the object to the end of the list L.

count

L.count( value) returns an integer representing the number of times "value" occurs in the list.

extend

L.extend( list) adds the elements of "list" to the end of L.

index

L.index( value) returns an integer that represents the index of the first occurrence of value in the list.

insert

L.insert(index, object) inserts object into the list L at the specified index and shifts all elements of the list at that index and greater up one.

pop

L.pop([index]) removes an object from the list and returns it. If no index is provided, the last element of the list is used.

remove

L.remove(value) removes the first occurrence of the specified value from the list L.

reverse

L.reverse() reverses the order of the list in place. There is no return value as this operation is done on the list in place.

sort

L.sort([cmpfunc]) sorts the list in place. If a cmpfunc is provided, it should compare two values (x, y) such that it returns a negative number if x is less than y, 0 if x equals y, and a positive number if x is greater than y.

The letter L is used to represent the PyList instance.

As with numeric classes, Jython can use all of Java's sequences without modification. PyString, PyTuple, and PyList are Jython-specific objects, but you can just as easily use a java. util. Vector. Note that slice notation and other Jython specific list attribute may not work on the Java sequence object you are using.

Mapping Objects

Jython has two mapping classes, or hash types, that are referred to as dictionaries. The "mapping" is the connection between an immutable key and another object—the value. The difference in Jython's two mapping classes is the type of key that is used. The values within a dictionary are accessed by supplying the key in square brackets, or by using one of the PyDictionary methods. The key notation appears as D[key], and an example usage looks like this:

>>>D = {"a":"alpha", "b":"beta"} >>>D["a"] 'alpha' >>>D["b"] 'beta' 


Mappings also have a length—a number that represents how many key:value pairs the mapping contains. The built-in function len() retrieves this value:

>>> D = {1:"a", 2:"b", 3:"c"} >>> len(D) 3 


PyDictionary

The PyDictionary class represents user-created dictionaries and is the parallel to the single dictionary type found in CPython. Curly braces are used to create a dictionary, and a colon is used to separate the key-value pair. Creating a PyDictionary bound to the name "D" looks like:

>>>D = {"String type key": "String", 1:"int", 2.0:"float"} >>>type(D) <jclass org.python.core.PyDictionary at 1272917> 


The keys in the preceding dictionary are different types, but all of the types are immutable. A mutable type that compares by value cannot be a PyDictionary key as noted by the exception it creates:

>>> L = [1,2,3,4] # create a list (mutable sequence) >>> D = {L:"My key is a list"} #Try to make L the key Traceback (innermost last): File "<console>", line 1, in ? TypeError: unhashable type 


Another important note on keys is that numerical values used as keys are hashed according to how their values compare. The PyInteger 1 is a different object than the PyFloat 1.0, but they compare as equal and thus function as the same key in a dictionary.

>>> A = 1 >>> B = 1.0 >>> C = 1+0j >>> eval("A==B==C") # Note: the integer 1 means true 1 


The three preceding numeric values evaluate to being equal. In this case it also means that they hash to the same value:

>>> hash(A)==hash(B)==hash(C) 1 # This means true 


This means using those values as dictionary keys would be interpreted as the same key.

>>>D = {1: "integer key", 1.0: "float key", 1+0j: "complex key"} >>>D # dump the value of D to prove that there was really only one key {1: 'complex key"} 


Objects of type PyDictionary have nine methods associated with them. They are described in Table 2.4.

Table 2.4. PyDictionary Methods

Method

Description

clear

D.clear() removes all the key:value pairs from the dictionary D.

copy

D.copy() returns a shallow copy of the dictionary D.

get

D.get(key [,defaultVal]) returns the value associated with the specified key if it exists. If the dictionary does not have the specified key, it can return an optional default value instead.

has_key

D.has_key( key) returns 1 if the dictionary D does in fact have the specified key. If not, it returns 0.

items

D.items( ) returns a copy of all the key:value pairs in dictionary D.

keys

D.keys() returns a list of all the keys in dictionary D. The list is a copy of D's keys, so changes to this list do not affect the keys in the original dictionary.

setdefault

D.setdefault(key [, defaultVal] ) returns the value associated with the specified key. If that key does not exist, and the optional defaultVal is provided, the specified key is added with defaultVal as its associated value and defaultVal is returned.

update

D.update( dict) updates all the key:value pairs in dictionary D with all the key:value pairs found in the dict parameter. Keys that did not exist in D are added and keys that did exist in D are updated with the values from the dict parameter.

values

D.values() returns a list of all the values in dictionary D. The list is a copy of D's values, so changes to this list do not affect the values in the original dictionary.

The variable D is used to represent the PyDictionary instance.

PyStringMap

Jython's PyStringMap class is a dictionary that uses only strings for keys. This is in contrast to the PyDictionary that can use any immutable object for a key. This is not an object normally created by the Jython programmer, but is the object returned by a number of built-in functions. It exists for the performance advantage such restricted keys provides. The PyStringMap is mostly used for namespaces where it makes sense for the keys to be strings. Therefore, the built-in functions that return namespace information return a PyStringMap object. These functions are locals(), globals(), and vars(). Additionally, Jython objects maintain object attributes in a PyStringMap named __dict__. Examine these in the interactive interpreter to see the PyStringMap usage:

>>># Fill up namespace so there's something to look at >>>functional = ['Erlang', 'Haskell'] >>>imperative = ['C++', 'Java'] >>> >>>globalStringMap = globals() >>>type(globalStringMap) <jclass org.python.core.PyStringMap at 6965863> >>> # Now let's look at the global namespace contents with a "print" >>> # Your global namespace may differ significantly if you have >>> # been doing other exercises in the same interpreter session. >>>print globalStringMap {'globalStringMap': {...}, '__name__': '__main__', '__doc__': None, 'imperative': ['C++', 'Java'], 'functional': ['Erlang', 'Haskell']} >>> >>>class test: ... pass ... >>>testNames = vars(test) >>>type(testNames) <jclass org.python.core.PyStringMap at 6965863> >>>print testNames {'__module__': '__main__', '__doc__': None} >>> >>>type(test.__dict__) <jclass org.python.core.PyStringMap at 6965863> 


PyStringMap and PyDictionary are Jython-specific mapping classes. However, all of Java's mapping classes are also available in Jython.

PyNone

The lack of a value is represented by the built-in object None. None is used in Jython as null is used in Java. The PyNone class is the object that represents this type. PyNone is a subclass of an internal object called PySingleton. This means that there is only one, single object of type PyNone. A PyNone instance evaluates to false in conditional statements and has no length:

>>>type(None) <jclass org.python.core.PyNone at 3482695> >>>a = None >>>len(a) Traceback (innermost last): File "<console>", line 1, in ? TypeError: len() of unsized object >>>if a: ... print "This will not print because a evaluates to false." ... >>> 


Operators

Operators are divided into five categories: arithmetic operators, shift operators, comparison operators, Boolean operators, and sequence operators. The type of object that an operator can be used with is included in its description by including the specific classes it works with or categories of types, such as "numeric" for PyInteger, PyLong, PyFloat, and PyComplex, "sequence" for PyList, PyTuple, and PyString, and "dictionary" for, of course, PyDictionary.

Arithmetic Operators

The first three of the numeric operators are unary so their descriptions are based on the assumption they prefix a single variable, x. The last six operators are binary and are described according to what the expression "x operator y" yields. The arithmetic operators are listed in Table 2.5.

Table 2.5. Arithmetic Operators

Operator

Description

- (x)

The unary minus operator produces the negative of the numeric object it prefixes and applies only to numeric objects.

+ (+ x)

The unary plus operator leaves the numeric object x unchanged and also applies to numeric objects only.

~ (~x)

The unary inversion operator yields the bit-inversi on of x (algebraic equivalent –(x +1)). This may be used on PyInteger and PyLong objects only.

+ (x+ y)

The addition operator yields the sum of two numeric objects. Note that addition applies to numeric objects, but the + sign is also used to join sequence objects as noted in the section on sequence operators.

- (xy)

The subtraction operator yields the difference between two numeric objects.

* (x*y)

The multiplication operator yields the product of x times y. This applies to numeric objects, but the * operator is also used with sequences as noted in that section.

** (x** y)

The power-of operator yields the value of x to the power of y and applies to all numeric objects.

/ (x/y)

The division operator yields the quotient of x divided by y. The division operator works for all numeric objects except for y =0, of course, which raises a ZeroDivisionError exception.

% (x%y)

The modulo operator yields the remainder for x divided by y. Modulo works for all numeric objects except for y =0, which raises a ZeroDivisionError exception.

The variable D is used to represent the PyDictionary instance.

Shift Operators

The shift operators apply to numeric objects. Table 2.6 lists the shift operators.

Table 2.6. Shift Operators

Operator

Description

x<< y

The left shift operator, which yields the binary result of shifting all bits y values to the left.

x>> y

The right shift operatory, which yields the binary result of shifting all bits y spaces to the right.

x& y

The bitwise AND operator, which yields the bitwise AND of x and y.

x|y

The bitwise OR operator, which yields the bitwise OR of x and y.

x^ y

The bitwise exclusive OR operator, which yields the XOR of x and y.

Comparison Operators

Comparison operators require an understanding of what is true and false. In Jython, false is the numeric 0, None, an empty list, empty tuple or an empty dictionary. Anything else is true. The comparison operators (see Table 2.7) themselves yield the integer 1 for true and 0 for false, and they can be used on any type of Jython object—numeric, sequence, or dictionary.

Table 2.7. Comparison Operators

Operator

Description

<

Less than

>

Greater than

==

Equal

>=

Greater than or equal

<=

Less than or equal

!=

Not equal

<>

Another spelling for not equal. This spelling is considered obsolete so its use is discouraged.

is object identity match.

"x is y" yields 1 if the object x is the same as the object y. "id" is a built-in function that returns the id of an object, so "is" is a shortcut for id (x)==id(y).

is not object identity mismatch.

"x is not y" yields 1 (true) if the object identity for x is not the same as the object identity for y.

in sequence membership.

"x in L" returns 1 (true) if x is a member of the sequence L.

not in sequence exclusion.

"x not in L" returns 1 (true) if x is not a member of the sequence L.

Boolean Operators

These Boolean operators (see Table 2.8) add conditions for truth evaluation.

Table 2.8. Boolean Operators

Operator

Description

not

A Boolean operator that returns 1 if the argument is false.

or

A Boolean operator that returns the value of the first argument if it evaluates to true. If not, the value of the second argument is returned.

and

A Boolean operator that returns the value of the first argument if it evaluates to false, but returns the value of the second argument if the first evaluates to true.

Sequence Operators

Table 2.9 shows the operators for sequence objects. Listing 2.2 shows how to concantentate the sequences.

Table 2.9. Sequence Operators

Operator

Description

+

Used to concatenate sequences. Listing 2.2 shows concatenation used with each of Jython's sequence objects.

*

The repeat operator when used with sequences. The syntax is: sequence * multiplier. The multiplier is the number of times the sequence should be repeated, so it must be a whole number. This means it can only be a PyInteger or PyLong object. Example usage is as follows:

>>> L = [1] * 3
>>> L
[1, 1, 1]
Listing 2.2 Concatenating Sequences
>>>var1 = "This, " >>>var2 = 'that, " >>>var1 + var2 + "and the other thing." "This, that, and the other thing. >>> >>>L = ["b", "e", "a"] >>>L + ["d", "g"] ['b', 'e', 'a', 'd', 'g'] >>> >>>T1 = (1, 1.1, 1.0+1.1j) >>>T2 = (1L, "one", ["o", "n", "e"]) #notice list within the tuple >>> T1 + T2 (1, 1.1, (1+1.1j), 1L, 'one', ['o', 'n', 'e']) 


Despite not being operators, string format characters are important to Jython's string processing ability and are included here. Jython also supports string format characters of the type used in C's printf function. These are placeholders appearing within a string, which consist of a % sign and a letter. For example, %s is a placeholder that can be supplanted by a string value external to the string itself. These characters are replaced with values when the string is followed by a % and a tuple or dictionary containing the required values. Table 2.10 shows a list of the format characters available and the data type they support.

Table 2.10. String Format Characters

Character

Jython type

% c

Character.

% d

Integer (originally signed decimal integer in C's printf).

% e

Floating-point number in scientific notation using the lowercase "e".

% f

Floating point number.

% g

Floating point number formatted like %e or %f depending on which is shorter.

% i

Integer.

% o

Unsigned octal integer.

%r

The string representation of the object provided. The representation is determined from the use of the built-in function repr().

% s

String.

% u

Unsigned integer (originally unsigned decimal integer in C's printf).

% x

Unsigned hexadecimal integer with letters in lowercase.

%E

Floating point number, PyFloat, converted to scientific notation using the uppercase "E".

% G

Floating point number formatted like %E or %f depending on which is shorter.

% X

Unsigned hexadecimal integer with letters in uppercase.

% %

A literal % .

Values supplied to formatted strings at conversion time can be within a dictionary or a tuple. If a tuple is used, the format characters are interpolated in the order they occur with the values from the tuple in the order they occur. This syntax looks like this:

>>>"Meet the %s at %i o'clock" % ("train", 1) "Meet the train at 1 o'clock" 


As format strings become larger, the sequential conversion get a bit unwieldy. To handle that, Jython allows dictionaries to supply the values to format strings. The dictionaries key, however, must be supplied within parentheses in the string. An example of this syntax appears as follows:

>>>D = {"what":"train", "when":1} >>>"Meet the %(what)s at %(when)i o'clock" % D "Meet the train at 1 o'clock" 


The key name becomes a useful clue when you run into errors or confusion in longer strings.

Built-Ins

Jython's built-ins, as the name implies, are the exceptions, functions, and variables available in Jython without any user-defined objects. This section includes the functions and variables only, while exceptions are reserved for , "Errors and Exceptions." Jython's built-in functions are a rich set of tools that streamline introspection, type manipulation, and dynamic execution. These abilities are also the organization of this section.

Introspection Functions

Introspection is the information a language provides about itself. Java has the reflection API for this. Jython provides its introspection through built-in functions. A rough categorization of the introspective functions is those that inspect objects, and those that show what objects are defined. Each object in Jython has a type and id that can be retrieved from the built-in functions type() and id(), respectively. These functions are defined as shown in Table 2.11.

Table 2.11. Object Inspection Functions

Function

Description

type(object)

Returns the type of the specified object as a name of one of the classes from the org.python.core package.

id(object)

Returns an integer representing the unique identification of the specified object.

Suppose you have a string object called S. Retrieving the type and id of S looks like this:

>>>S = "String object" >>>type(S) <jclass org.python.core.PyString at 1272917> >>>id(S) 2703160 >>>S2 = S >>>id(S2) # to prove S2 is a reference to the same object 2703160 


Examining a built-in function, rather than a string, works the same way. Take a look at the built-in function type.

>>>type(type) <jclass org.python.core.PyReflectedFunction at 2530155> >>>id(type) 2804756 


PyReflectedFunction is one of the Py* classes from org.python.core not discussed in this chapter. It is obviously a function type, considering function is part of the type name, and should be callable. After all, the example called it to retrieve its own type. Knowing an object is callable is not always the case though. Fortunately Jython has the built-in function callable(object). callable(object) returns 1 or 0 (true or false) as to whether the object in question is a callable object.

>>>callable(type) # Is the built-in function "type" callable? 1 >>>callable(S) # Is the string "S" callable? 0 


The built-in function callable() does not always tell the truth about Java objects however, and cannot always be trusted. The type, id, and callable functions examine object attributes. However, you do not always know which objects are defined. There are built-in functions that examine just that—what names bindings exist. These functions are dir(), vars(), globals(), and locals(). Fully understanding these requires a better understanding of Jython's namespaces than is offered in this chapter. ,"User-Defined Functions and Variable Scoping," contains the details about Jython's namespaces.

dir([object])

Returns a list of names defined in the object specified, or names in the current scope if no object is specified.

vars([object])

Returns a dictionary of bound names within the specified object. This is actually the objects own internal __dict__ object that will be discussed with Jython class definitions later on. The vars function only works on objects with a __dict_ _ attribute. If no object is specified, it does the same as locals().

globals( )

Returns a dictionary like object representing the variables defined in the global namespace.

locals( )

Returns a dictionary like object representing the variables defined in the local namespace.

Listing 2.3 includes a function definition and a class definition so we can make use of locals() and vars(). The def is what creates a function and the class keyword creates a class. Note that the exact output you get when trying Listing 2.3 may differ. Variations in output may result from previous interactive experimentation or other inconsequential reasons.

Listing 2.3 Exploring Namespaces
>>>def test1(): ... "A function that prints its own local namespace" ... avariable = "Inside test function" ... print locals() ... >>> class test2: ... "An empty class" ... pass ... >>> dir() # look at list of global names ['__doc__', '__name__', 'test1', 'test2'] >>> >>> globals() # look at global names and values {'test2': <class __main__.test2 at 5150801>, '__name__': '__main__', '__doc__': None, 'test1': <function test1 at 7469777>} >>> >>> dir(test1) # look at names in the test function ['__doc__', '__name__', 'func_code', 'func_defaults', 'func_doc', 'func_globals', 'func_name'] >>> >>> dir(test2) # look at list of names in the class ['__doc__', '__module__'] >>> >>> test1() # invoke method that prints locals() {'avariable': 'Something to populate the local namespace'} >>> >>> vars(test2) # user-defined classes have a __dict__, so vars works {'__module__': '__main__', '__doc__': None} 


This attribute inspection is not limited to Jython-only objects. The greatness of Jython is that it equally applies to Java objects. The statement import java makes the root java package available in Jython. Then all that is Java can be inspected in the same manner. Listing 2.4 inspects java. util. ListIterator. This is a familiar interface, but lets assume it is a newly downloaded package you wish to explore. You can traverse contents of each level of the package with dir(package) to see what is in them. All this can be done interactively in Jython as demonstrated in Listing 2.4. The actual output from Listing 2.4 will differ depending on your version of Java.

Listing 2.4 Exploring Java Packages
>>> import java >>> dir(java) ['__name__', 'applet', 'awt', 'beans', 'io', 'lang', 'math', 'net', 'rmi', 'security', 'sql', 'text', 'util'] >>> dir(java.util) ['AbstractCollection', 'AbstractList', 'AbstractMap', 'AbstractSequentialList', 'AbstractSet', 'ArrayList', 'Arrays', 'BitSet', 'Calendar', 'Collection', 'Collections', 'Comparator', 'ConcurrentModificationException', 'Date', 'Dictionary', 'EmptyStackException', 'Enumeration', 'EventListener', 'EventObject', 'Gregorian Calendar', 'HashMap', 'HashSet', 'Hashtable', 'Iterator', 'LinkedList', 'List', 'ListIterator', 'ListResourceBundle', 'Locale', 'Map', 'MissingResourceException ', 'NoSuchElementException', 'Observable', 'Observer', 'Properties', 'PropertyPermission', 'PropertyResourceBundle', 'Random', 'ResourceBundle', 'Set', 'SimpleTimeZone', 'SortedMap', 'SortedSet', 'Stack', 'StringTokenizer', 'TimeZone', 'Timer', 'TimerTask', 'TooManyListenersException', 'TreeMap', 'TreeSet', 'Vector', 'WeakHashMap', '__name__', 'jar', 'zip'] >>> dir(java.util.ListIterator) ['', 'add', 'hasPrevious', 'nextIndex', 'previous', 'previousIndex', 'set'] >>> test = java.util.ListIterator() # try calling it anyway Traceback (innermost last): File "<console>", line 1, in ? TypeError: can't instantiate interface (java.util.ListIterator) 


Numeric Functions

The built-in numeric functions are convenience functions for common math operations. These six functions are shown in Table 2.12.

Table 2.12. Built-In Numeric Functions

Function

Description

abs(x)

Returns the absolute value of the number x.

divmod(x, y)

Returns both the division and modulus of x divided by y (for example, 2/3, 2%3).

hex(x)

Returns the hexadecimal representation of the integer x as a string.

oct(x)

Returns the octal representation of the integer x as a string.

pow(x, y [,z])

Returns x**y. If z is provided, it returns x**y % z.

round(x [, ndigits])

Returns PyFloat number representing the number x rounded to 0 decimal places. If the optional ndigits is provided, x is rounded to the ndigits from the decimal. Negative ndigits numbers mean left of the decimal; positive mean right of the decimal. Currently, in Jython 2.0, the ndigits argument must be an integer. This differs slightly from the CPython implementation where it can be any number that can be converted to an int.

Type Conversion Functions

Conversion of Java types requires type casts—something that is usually pervasive in Java programs. In Jython, such type conversions are handled with built-in functions. These functions are named according to the object returned. This simplicity makes definition unnecessary—an example of this is sufficient to clarify their usage. Listing 2.5 shows each of the type conversion functions: int, long, float, complex, tuple, and list.

Listing 2.5 Type Conversions
>>>int(3.5) 3 >>>long(22) 22L >>>float(8) 8.0 >>>complex(2.321) (2.321+0j) >>>tuple("abcdefg") ('a', 'b', 'c', 'd', 'e', 'f', 'g') >>>list("abcdefg") ['a', 'b', 'c', 'd', 'e', 'f', 'g'] 


coerce(object1, object2) is also a built-in function. The coerce function takes two objects as parameters, tests if the values of these objects can be represented in a common object, and returns the two values in a tuple of same-type objects. If it is not possible to represent the values as a common type, coerce returns the object None. A float and integer value can both be represented by a float:

>>>coerce(3.1415, 6) (3.1415, 6.0) 


However, a string and float cannot be represented as the same type:

>>>results = coerce("a", 2.3) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: number coercion failed 


The Built-in File Function

There is only one built-in file function. That function is open. The open function returns a file object that can be read from or written to. The syntax for the open functions is as follows:

open(filepath [, mode [, buffer]]) 


filepath is the platform specific path and filename to the file that is being opened. The mode symbol supplied to the open function determines whether the file is open for reading, writing, appending, or both reading and writing. This mode option also specifies if this is a text or a binary file. Text mode implies the platform specific new-line translations. Binary mode implies just binary data, so no newline translations and only the low-order byte of Unicode characters are used. Binary mode must be explicitly specified to write binary data in Jython, otherwise Unicode characters will pass through the default java codec to and from the file. Note that the mode setting is optional in the open function, and when not specified, the default mode of reading text is used. The symbols used in the mode argument are as follows:

r = reading

w = writing

a = appending

+ = designates both reading and writing when added to "r","w" or "a" (e.g."r+", "w+" or "a+")

b = binary mode

The optional buffer argument to the open function is currently ignored.

Sequence Functions

These built-in functions either require a list type as a parameter or return a list except for the string specific functions. The functions specific to the PyString sequence are intern, chr, unichr, and unicode, and are described in Table 2.13.

Table 2.13. PyString-Specific Functions

Function

Description

intern(string)

This places the specified string in a PyStringMap of long-lived strings. The reason being it should provide performance advantages in dictionary lookups.

chr(integer)

For integers <= 65535, chr returns the character PyString of length 1) that has the specified integer value.

ord(character)

This function is the opposite to chr(integer) (see preceding list item). For character c, chr(ord(c))==c.

unichr(integer)

This does the same as chr. These two methods, chr and unichr, exist for compatibility with CPython.

unicode(string [, encoding[, errors]])

This function creates a new PyString object using the encoding specified. The available encodings are found in Jython Lib directory within the encodings folder. The optional errors argument can be either strict, ignore, or replace.

The functions that work on any Jython sequence object are described in Table 2.14.

Table 2.14. Built-In Sequence Functions

Function

Description

max(sequence)

Returns the greatest value within the sequence.

min(sequence)

Returns the least value within the sequence.

slice([start,] stop[, step])

The slice function is a synonym for sequence slice syntax. It is used by extensions, mainly.

range([start,] stop [,step]) and xrange([start,]stop [,step])

The range and xrange functions are used to generate lists. The of these functions are the same; however, their implementation differs. The range function builds and returns a list of integers, while the xrange function returns an xrange object that supplies integers as needed. The idea is that xrange is an advantage for very large ranges. All arguments for range must be integers (PyIntegar or PyLong). Counting starts at the designated start number, or 0. Counting continues to, but not including, the designated stop integer. If the optional step argument is provided, it is used as the increment number. Examples best clarify range and xrange:

>>>range(4)
[0, 1, 2, 3]
>>>range(3, 6)
[3, 4, 5]
>>>range(2, 10, 2)
[2, 4, 6, 8]
>>>xrange(4)
(0, 1, 2, 3)
>>>type(xrange(4)) # check the type returned from xrange
<jclass org.python.core.PyXRange at 7991538>
>>>type(range(4)) # check the type returned from range
>>> type(range(4))
<jclass org.python.core.PyList at 7837392>
>>>range(10, 0, -1) # use range to count backwards
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

Dynamic Language Functions

Jython's dynamic language functions allow dynamic code generation, compilation and execution with functions like compile, apply, execfile, and eval. They are not addressed here because the brevity with which they would be treated at this point in the tutorial would only provide confusion.

Attribute Tools

Jython has a rich set of built-in functions for working with Jython classes and their attributes. For attributes specifically, there are the hasattr, delattr, getattr, and setattr functions. Parameters for hasattr, delattr, and getattr are all object, attribute (such as hasattr( object, attribute)). setattr requires an additional (third) parameter which is the value the specified attribute should be set to. Jython class attributes are normally accessed with dot notation much like Java's. If object A contains attribute b, the syntax for accessing attribute b is A.b:

>>> class A: ... b = 10 ... >>> A.b 10 


Jython's attribute tools exist as an alternative way of working with object attributes, but they are definitely less common that the traditional dot notation. This section walks through the usage of these built-in functions on two objects. The first of these objects is an empty Jython class, but the second is a Java class that has nothing but a public instance variable— var1. The catch with Java classes is that they are not as flexible as a Jython class. Arbitrary attributes cannot be added or deleted from Java classes. Start by creating and empty Jython class:

>>>class JythonClass: ... pass 


Next, make an instance of the new class so we have an object to use hasattr, setattr, and getattr on:

>>>jyInstance = JythonClass() 


The hasattr function checks whether an object contains an attribute. The object and attribute name are also the hasattr function's parameters. To check for the attribute var1 in our instance named jyInstance, use this:

>>>hasattr(jyInstance, "var1") 0 


The result you get is zero, or false. var1 is not currently defined. Now let's assume we want to define, or "set" it. While an assignment would work to do this, there is also the setattr function. setattr requires three parameters: the object, the attribute name, and the value to bind to the attribute name. Setting a jyInstance attribute named var1 to a string value looks like this:

>>>setattr(jyInstance, "var1", "A new value for var1") 


Now use hasattr to check again for "var1" within jyInstance:

>>>hasattr(jyInstance, "var1") 1 


The result of 1, or true, confirms var1 is there. Now that jyInstance has an attribute, we can use getattr to retrieve its value. The getattr function requires the object and attribute name as parameters:

>>>getattr(jyInstance, "var1") 'A new value for var1' 


The getattr() function also works for accessing members in classes and objects in modules:

>>> import os >>> getattr(os, "pathsep") # get a variable from a module ';' >>> getattr(os, "getcwd")() # call a function within a module 'C:\\WINDOWS\\Desktop' 


And finally, the attribute may be deleted with delattr:

>>>delattr(jyInstance, "var1") >>>hassattr(jyInstance, "var1") 0 


Java classes differ from Jython classes, however. Forget the preceding Jython example and continue anew with a Java class. Assume the java class definition is as follows:

public class JavaClass {
 public String var1; public void JavaClass() {} } 


Also assume that JavaClass is compiled with javac and that it is in the current directory from which you start Jython. You can use JavaClass to show how Jython's built-in attribute functions also work on Java objects. Start by importing JavaClass and creating an instance of it:

>>>import JavaClass >>>javaInstance = JavaClass() 


Now use hasattr to test for the existence of the attribute var1 in JavaClass:

>>>hasattr(javaInstance, "var1") 1 


Now that the existence of var1 is confirmed, change it a few times with setattr and test the new value with getattr:

>>>setattr(javaInstance, "var1", "A new value for var1") >>>getattr(javaInstance, "var1") # check out the new value 'A new value for var1' >>>setattr(javaInstance, "var1", "Yet another value") >>>getattr(javaInstance, "var1") 'Yet another value' 


So far the Java object works the same as the Jython object. The difference appears when you try to delete an attribute, or when you try to add an arbitrary attribute. First, can you delete var1 ?

>>>delattr(javaInstance, "var1") Traceback (innermost last): File "<console>", line 1, in ? TypeError: can't delete attr from java instance: var1 


That's a no. Can you add an arbitrary attribute?

>>># Can we add another arbitrary attribute >>>setattr(ja, "var2", "Value for var2") Traceback (innermost last): File "<console>", line 1, in ? TypeError: can't set arbitrary attribute in java instance: var2 


No, yet again. Continue object inspection with a different Java class: java. util. Vector. First, import and create an instance of Vector like this:

>>>import java >>>v = java.util.Vector() # import a well-known java class 


Inspect the Vector instance for the attribute toString:

>>>hasattr(v, "toString") # in case you forgot 1 


Object inspection includes testing whether an instance is part of a specific class. The built-in isinstance function determines this for the instance and class supplied as arguments:

>>>isinstance(v, java.util.Vector) 1 


If the result had instead been zero, it would mean that v is not an instance of java.util. Vector. Note from Listing 2.6 that the built-in function isinstance returns 1 or 0 (true or false) for whether the instance is in fact an instance of the supplied class. Syntax is isinstance( instance, class).

Functional Tools

Elements from functional coding show up in Jython's built-in functions. These functions work with lists and are filter, map, reduce, and zip. All of these built-in functions require another function as their first parameter, so discussion of these is reserved until the chapter on Jython functions.

Miscellaneous Functions

Some built-in functions, while equally useful, are less easily categorized than others. As these have no special relationship, it is best to provide just a list of functions and their definitions, including examples where it benefits clarity. Table 2.15 provides these miscellaneous functions.

Table 2.15. Miscellaneous Functions

Function

Description

cmp(x, y)

The compare function, cmp, requires two parameters to compare. A value of –1, 0, or 1 is returned based on whether x<y, x= = y, or x>y, respectively.

len(object)

len returns the length of a sequence or mapping object. It would have been included with the sequence functions if it didn't also work on mapping objects.

repr(object)

repr returns a string representation of an object that is useful in reconstructing that object. Suppose you need a string representation of a java.lang.Vector object. The repr function provides this as noted in this brief example:

>>>>>> import java
>>> v = java.util.Vector()
>>> repr(v)
'[]'
>>> v.add("A string")
1
>>> v.add(4)
1
>>> v.add([1,2,3,4,5])
1
>>> repr(v)
'[A string, 4, [1, 2, 3, 4, 5]]'

str(object)

str returns a string that describes the specified object. This differs from repr in that this string can be a description or label rather than the more strict representation of data expected from repr().

reload( module)

This function is self-evident, but its usefulness isn't immediately evident. This function allows you to work something out in interactive mode, switch to an editor to change a module as needed, then return to interactive mode to reload the altered module.

raw_input([prompt] )

The raw_input function reads a string from standard input with the trailing newline removed:

>>>>>> name = raw_input("Enter your name: ")
Enter your name: Robert
>>> print name Robert

input([prompt] )

This is the same as raw_input except that what is entered at the prompt is evaluated.

>>> input("Enter a Jython expression: ")
Enter a Jython expression: 2+3
5 <-- the evaluated result of 2+3

hash( object)

Two objects with the same value have the same hash value. This hash value is retrieved with the built-in hash function.

Comparison of Jython Data Types and Java Data Types

What is the difference between Java's data types and Jython's? Java is a strictly typed language where data values are stored in objects that have an explicitly specified type. The following Java statement clearly creates an object bound to the name myString of type java.lang.String with the self-aware value I'm a string:

String myString = "I'm a string"; 


Jython is also a strongly typed language in which data is represented by objects of a specific type. The big difference is that Jython is dynamically typed. Unlike the preceding little Java snippet, Jython does not use explicit type information in its code. Therefore, that information is not available at compile time. Instead, Jython eagerly determines types based on assigned values at runtime. What does this difference in typing mean? It's good to be wary of oversimplifications of type systems, but with that said—Java explicit typing means that Java compilers can make certain assumptions about a variable at compile time. This allows for many optimizations and compile-time type-safety checks. For Jython's dynamic types, it means flexible, high-level data objects that allow for compact code, increased clarity of program logic, and often increased programmer productivity. In short, Jython data objects help provide great flexibility at the expense of compile-time optimizations.

Java Types

The primary advantage of Jython is the ability to use Java classes without modification. This creates problems with converting types from Java's types to Jython's. Java is type-rich. Methods, constructors, and variables use types. Jython, on the other hand, is free of primitive types, has data objects that are not native in Java, and determines types dynamically. This means Jython's types require translation to Java types for method arguments, and translation from Java types for method return values. Jython automatically translates types according to Table 2.16.

Table 2.16. Type Translations Between Java and Jython

Java

Jython

Char

PyString of length 1

Byte

PyInteger

Short

PyInteger

Int

PyInteger

Long

PyInteger

Float

PyFloat

Double

PyFloat

java.lang.String

PyString

byte[]

PyString

char[]

PyString

PyObject

PyObject

A java class

PyJavaClass, which represents the given Java class.

An instance of a Java class

PyInstance of the Java class identified in instance.__class_ _. For example:

>>> from java.lang import Double
>>> d = Double(2.0)
>>> d.__class__
<jclass java.lang.Double at 3291150>

Boolean

PyInteger (When translating from a Jython PyInteger to a Java Boolean,0 == false and nonzero == true. When translating from a Java Boolean to a Jython type, true == 1 and false == 0.)

java.lang.Object

java.lang.Object

These types translate consistently. The specified Jython object works when its corresponding Java type appears in a method signature, and a returned Java type converts to its corresponding Jython class.

Java method parameters or return values may also be an instance of a Java class or an array of a Java class. If a method specifies the Java class A as a parameter type, you can instantiate and supply an instance of A, an instance of a Java subclass of A, or a Jython subclass of A to meet the requirement. If an instance of A is the return type of a Java method, Jython turns that into a PyInstance of A or whatever subclass of A was returned. If an array of a Java objects is expected in a Java method signature, you must supply an array containing objects created from the class or subclass of the specified object. To create a Java array, you must use the jarray module. The jarray module contains two functions: array and zeros. The array function requires two arguments:the first is a sequence, and the second is a code letter that designates the type of the array. The length of the array equals the length of the supplied sequence. Note that the sequence must contain objects of the same type. A sequence can be a string, list, or tuple as appropriate. To create a character array (char[] in Java), first import the jarray module, then supply a sequence of characters as the first parameter, and the type code c as the second parameter like this:

>>> import jarray >>> myJavaArray = jarray.array("abcdefg", "c") >>> myJavaArray array(['a', 'b', 'c', 'd', 'e', 'f', 'g'], char) >>> myJavaArray = jarray.array(['a','b','c','d'], 'c') >>> myJavaArray array(['a', 'b', 'c', 'd'], char) 


The Java "class" of an array type may also be used to designated the array's type in the second argument to the jarray.array function. For Java primitive data types, this means the java.lang class that wraps the primitive type. To make an int [ ] array from a Jython PyList, you could use the following:

>>> import jarray >>> import java # Required to see the java.lang.Integer class >>> myIntArray = jarray.array([1,2,3,4,5,6,7,8,9], java.lang.Integer) array([1, 2, 3, 4, 5, 6, 7, 8, 9], java.lang.Integer) >>> i = java.lang.Integer(1) 


To create an array of a specific length and type, but only 0, or null, values, use the function jarray.zeros. The jarray.zeros function also requires two arguments: the first is the length of the array, and the second the type code or class which designates the array type. An example of using jarray.zeros to create a java byte [ ] of length ten looks like this:

>>> import jarray >>> byteArray = jarray.zeros(10, "b") >>> byteArray array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], byte) 


The list of all the type codes, their associated Java types, and classes from the java.lang package for those types appear in Table 2.17.

Table 2.17. Array Typecodes, Types, and Classes

Typecode

Java Type

Type Wrapper Class

z

Boolean

java.lang.Boolean

c

char

java.lang.Character

b

byte

java.lang.Byte

h

short

java.lang.Short

i

int

java.lang.Integer

l

long

java.lang.Long

f

float

java.lang.Float

d

double

java.lang.Double

For arrays of classes without a typecode, use the class to designate the array type. For example, a Data [ ] for the class java. util. Data can be created with the following:

>>> import java >>> import jarray >>> myDateArray = jarray.zeros(5, java.util.Data) >>> myDateArray array([None, None, None, None, None], java.util.Date) 


When you encounter difficulty in calling a specific Java method signature due to limitations on type translations and overloaded methods, the best solution is to create an instance of the Java type's object wrapper. If a PyInteger doesn't convert properly to call a method signature requiring an short type, force proper recognition by first creating an instance of the short type's object wrapper java. lang. Short. Assume method A is overloaded with one signature A(short s) and another A( int i) and calling the short signature is not working.The following example demostrates how to correct this:

>>> import java >>> myPyInt = 5 >>> myJavaShort = java.lang.Short(myPyInt) >>> ## Here you could call the hypothetical method "A(myJavaShort)" 


Screenshot CONTENTS Screenshot
Comments