The Definitive Guide To Jython
User Manual:
Open the PDF directly: View PDF
.
Page Count: 545
| Download | |
| Open PDF In Browser | View PDF |
CYAN
MAGENTA
YELLOW
BLACK
PANTONE 123 C
BOOKS FOR PROFESSIONALS BY PROFESSIONALS ®
Dear Reader,
With Jython you enjoy the increased productivity and clarity of Python, and
the ability to integrate with existing Java™ libraries. You get the best of both
worlds: the elegance of Python, and the enterprise-readiness and maturity of
the JVM. The Definitive Guide to Jython explores the Python programming language from the ground up, pointing out along the way details that are specific
to Jython. If you are unfamiliar with the Python language, then you can get
started here, but you will also learn about the differences between Jython and
standard CPython as you go.
Once you have the basics of the language, you’ll want to put it into use. This
book covers a variety of topics which will help you harness the power of Jython.
You will learn how to develop dynamic applications and scripts, and access databases from Jython to build powerful database applications. Fundamental to getting the most out of Jython is Java integration, and this book encourages you to
use Java within Jython code as well as Jython within Java code.
Jython has matured a lot between the last couple of versions and it is now
compliant with modern versions of the Python language. This means that you
can now take advantage of Python frameworks such as Django and Pylons, which
are both covered in this book. We will also provide you with a foundation to begin
using Java Servlet and Java Swing technologies with Jython.
We hope you enjoy this book and that it helps Jython to become as useful to
you as it is to us!
Companion eBook
SOURCE CODE ONLINE
ISBN 978-1-4302-2527-0
5 54 9 9
US $54.99
Juneau
Baker
Ng
Soto
Wierzbicki
www.apress.com
Available online at
www.jythonbook.com
RELATED TITLES
See last page for details
on $10 eBook version
Josh Juneau, Jim Baker, Victor Ng, Leo Soto, and Frank Wierzbicki
Companion
eBook Available
The Definitive Guide to Jython
The Definitive Guide to Jython:
Python for the Java™ Platform
THE EXPERT’S VOICE ® IN SOFTWARE DEVELOPMENT
Covers
Jython 2.5
The Definitive Guide to
Jython
Python for the Java™ Platform
Enjoy the power and flexibility
of Python on the JVM
Josh Juneau, Jim Baker, Victor Ng,
Leo Soto, Frank Wierzbicki
Foreword by Ted Leung
Shelve in:
Java, Python
User level:
Beginner – Intermediate
9 781430 225270
www.it-ebooks.info
this print for content only—size & color not accurate
spine = 1.03125" 544 page count
www.it-ebooks.info
The Definitive Guide to
Jython
Python for the Java™ Platform
■■■
Josh Juneau, Jim Baker, Victor Ng, Leo Soto, Frank
Wierzbicki
www.it-ebooks.info
■ CONTENTS AT A GLANCE
The Definitive Guide to Jython: Python for the Java™ Platform
Copyright © 2010 by Josh Juneau, Jim Baker, Victor Ng, Leo Soto, Frank Wierzbicki
All rights reserved. No part of this work may be reproduced or transmitted in any form or by any means,
electronic or mechanical, including photocopying, recording, or by any information storage or retrieval
system, without the prior written permission of the copyright owner and the publisher.
ISBN-13 (pbk): 978-1-4302-2527-0
ISBN-13 (electronic): 978-1-4302-2528-7
Printed and bound in the United States of America 9 8 7 6 5 4 3 2 1
Trademarked names may appear in this book. Rather than use a trademark symbol with every
occurrence of a trademarked name, we use the names only in an editorial fashion and to the benefit of
the trademark owner, with no intention of infringement of the trademark.
Java™ and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc., in
the US and other countries. Apress, Inc., is not affiliated with Sun Microsystems, Inc., and this book was
written without endorsement from Sun Microsystems, Inc.
President and Publisher: Paul Manning
Lead Editors: Steve Anglin, Duncan Parkes
Technical Reviewers: Mark Ramm, Tobias Ivarsson
Editorial Board: Clay Andres, Steve Anglin, Mark Beckner, Ewan Buckingham, Gary Cornell,
Jonathan Gennick, Jonathan Hassell, Michelle Lowman, Matthew Moodie, Duncan Parkes,
Jeffrey Pepper, Frank Pohlmann, Douglas Pundick, Ben Renow-Clarke, Dominic Shakeshaft,
Matt Wade, Tom Welsh
Coordinating Editor: Mary Tobin
Copy Editor: Tracy Brown Collins
Indexer: BIM Indexers and e-Services
Artist: April Milne
Cover Designer: Anna Ishchenko
Distributed to the book trade worldwide by Springer-Verlag New York, Inc., 233 Spring Street, 6th Floor,
New York, NY 10013. Phone 1-800-SPRINGER, fax 201-348-4505, e-mail orders-ny@springer-sbm.com, or
visit http://www.springeronline.com.
For information on translations, please e-mail info@apress.com, or visit http://www.apress.com.
Apress and friends of ED books may be purchased in bulk for academic, corporate, or promotional use.
eBook versions and licenses are also available for most titles. For more information, reference our
Special Bulk Sales–eBook Licensing web page at http://www.apress.com/info/bulksales.
The information in this book is distributed on an “as is” basis, without warranty. Although every
precaution has been taken in the preparation of this work, neither the author(s) nor Apress shall have
any liability to any person or entity with respect to any loss or damage caused or alleged to be caused
directly or indirectly by the information contained in this work.
This book is available online under the Creative Commons Attribution-Share Alike license
(http://creativecommons.org/licenses/by-sa/3.0/). You can read the book at http://jythonbook.com.
ii
www.it-ebooks.info
■
Contents at a Glance
Contents at a Glance...........................................................................................................................iii
Contents ............................................................................................................................................... v
Foreword ........................................................................................................................................... xix
About the Authors .............................................................................................................................. xx
About the Technical Reviewers....................................................................................................... xxii
Acknowledgments .......................................................................................................................... xxiii
Introduction..................................................................................................................................... xxvi
Part I: Jython Basics: Learning the Language ....................................................................................1
■ Chapter 1: Language and Syntax ....................................................................................................3
■ Chapter 2: Data Types and Referencing .......................................................................................25
■ Chapter 3: Operators, Expressions, and Program Flow ...............................................................59
■ Chapter 4: Defining Functions and Using Built-ins ......................................................................81
■ Chapter 5: Input and Output........................................................................................................105
■ Chapter 6: Object-Oriented Jython .............................................................................................113
■ Chapter 7: Exception Handling and Debugging..........................................................................133
■ Chapter 8: Modules and Packages for Code Reuse ...................................................................151
Part II: Using the Language .............................................................................................................163
■ Chapter 9: Scripting With Jython ................................................................................................165
■ Chapter 10: Jython and Java Integration ...................................................................................175
■ Chapter 11: Using Jython in an IDE ............................................................................................197
■ Chapter 12: Databases and Jython: Object Relational Mapping and Using JDBC ....................231
Part III: Developing Applications with Jython ................................................................................263
■ Chapter 13: Simple Web Applications ........................................................................................265
■ Chapter 14: Web Applications With Django................................................................................281
■ Chapter 15: Introduction to Pylons .............................................................................................327
■ Chapter 16: GUI Applications ......................................................................................................347
iii
www.it-ebooks.info
■ CONTENTS AT A GLANCE
■ Chapter 17: Deployment Targets ................................................................................................359
Part IV: Strategy and Technique......................................................................................................377
■ Chapter 18: Testing and Continuous Integration .......................................................................379
■ Chapter 19: Concurrency.............................................................................................................413
■ Appendix A: Using Other Tools with Jython ...............................................................................437
■ Appendix B: Jython Cookbook ....................................................................................................445
■ Appendix C: Built-in Functions ...................................................................................................463
Index.................................................................................................................................................485
iv
www.it-ebooks.info
■
Contents
Contents at a Glance...........................................................................................................................iii
Contents ............................................................................................................................................... v
Foreword ........................................................................................................................................... xix
About the Authors .............................................................................................................................. xx
About the Technical Reviewers....................................................................................................... xxii
Acknowledgments .......................................................................................................................... xxiii
Introduction..................................................................................................................................... xxvi
Part I: Jython Basics: Learning the Language ....................................................................................1
■ Chapter 1: Language and Syntax ....................................................................................................3
The Difference between Jython and Python........................................................................................ 4
Installing and Configuring Jython ....................................................................................................... 4
Identifiers and Declaring Variables ..................................................................................................... 5
Reserved Words................................................................................................................................. 6
Coding Structure ................................................................................................................................ 6
Operators........................................................................................................................................... 8
Expressions ....................................................................................................................................... 8
Functions........................................................................................................................................... 9
Classes ............................................................................................................................................ 10
Statements ...................................................................................................................................... 11
if-elif-else Statement ................................................................................................................... 12
print Statement............................................................................................................................ 13
try-except-finally ......................................................................................................................... 15
raise Statement ........................................................................................................................... 16
import Statement ......................................................................................................................... 17
Iteration ........................................................................................................................................... 17
While Loop................................................................................................................................... 19
For Loop ...................................................................................................................................... 20
Basic Keyboard Input ....................................................................................................................... 20
v
www.it-ebooks.info
■ CONTENTS
Other Python Statements ................................................................................................................. 21
Documenting Code........................................................................................................................... 22
Python Help ..................................................................................................................................... 23
Summary ......................................................................................................................................... 24
■ Chapter 2: Data Types and Referencing .......................................................................................25
Python Data Types ........................................................................................................................... 25
Strings and String Methods.......................................................................................................... 27
String Formatting..................................................................................................................... 31
Lists, Dictionaries, Sets, and Tuples............................................................................................. 33
Lists ........................................................................................................................................ 33
List Comprehensions ............................................................................................................... 40
Tuples ..................................................................................................................................... 41
Dictionaries ............................................................................................................................. 42
Sets......................................................................................................................................... 45
Ranges .................................................................................................................................... 48
Range Format .......................................................................................................................... 49
Jython-specific Collections .......................................................................................................... 50
Files............................................................................................................................................. 52
Iterators ....................................................................................................................................... 54
Referencing and Copies ............................................................................................................... 55
Garbage Collection....................................................................................................................... 57
Summary ......................................................................................................................................... 58
■ Chapter 3: Operators, Expressions, and Program Flow ...............................................................59
Types of Expressions ....................................................................................................................... 59
Mathematical Operations ................................................................................................................. 59
Comparison Operators ................................................................................................................. 63
Bitwise Operators ........................................................................................................................ 65
Augmented Assignment ............................................................................................................... 66
Boolean Expressions .................................................................................................................... 68
Conversions ................................................................................................................................. 70
Using Expressions to Control Program Flow...................................................................................... 72
if-elif-else Statement ................................................................................................................... 72
while Loop ................................................................................................................................... 73
continue Statement...................................................................................................................... 74
break Statement .......................................................................................................................... 75
vi
www.it-ebooks.info
■ CONTENTS
for Loop ....................................................................................................................................... 76
Example Code.............................................................................................................................. 77
Summary ......................................................................................................................................... 79
■ Chapter 4: Defining Functions and Using Built-ins ......................................................................81
Function Syntax and Basics.............................................................................................................. 81
The def Keyword.......................................................................................................................... 82
Naming the Function.................................................................................................................... 82
Function Parameters and Calling Functions.................................................................................. 84
Recursive Function Calls .......................................................................................................... 86
Function Body.............................................................................................................................. 86
Documenting Functions ........................................................................................................... 86
Returning Values...................................................................................................................... 87
Introducing Variables ............................................................................................................... 88
Other Statements..................................................................................................................... 89
Empty Functions ...................................................................................................................... 89
Miscellaneous Information for the Curious Reader............................................................................ 90
Built-in Functions............................................................................................................................. 90
Alternative Ways to Define Functions ............................................................................................... 90
Lambda Functions ....................................................................................................................... 91
Generator Functions......................................................................................................................... 91
Defining Generators ..................................................................................................................... 92
Generator Expressions ................................................................................................................. 95
Namespaces, Nested Scopes, and Closures ..................................................................................... 95
Function Decorators......................................................................................................................... 96
Coroutines ....................................................................................................................................... 99
Decorators in Coroutines............................................................................................................ 101
Coroutine Example..................................................................................................................... 102
Summary ....................................................................................................................................... 102
■ Chapter 5: Input and Output........................................................................................................105
Input from the Keyboard................................................................................................................. 105
sys.stdin and raw_input............................................................................................................. 105
Obtaining Variables from Jython Environment ............................................................................ 106
File I/O ........................................................................................................................................... 107
Pickle............................................................................................................................................. 110
Output Techniques..................................................................................................................... 111
vii
www.it-ebooks.info
■ CONTENTS
Summary ....................................................................................................................................... 112
■ Chapter 6: Object-Oriented Jython .............................................................................................113
Basic Syntax .................................................................................................................................. 113
Object Attribute Lookups................................................................................................................ 117
Inheritance and Overloading........................................................................................................... 119
Underscore Methods ...................................................................................................................... 121
Protocols........................................................................................................................................ 123
Default Arguments ......................................................................................................................... 127
Runtime Binding of Methods .......................................................................................................... 128
Caching Attribute Access ............................................................................................................... 128
Summary ....................................................................................................................................... 131
■ Chapter 7: Exception Handling and Debugging..........................................................................133
Exception Handling Syntax and Differences with Java .................................................................... 133
Catching Exceptions................................................................................................................... 134
Raising Exceptions..................................................................................................................... 142
Defining Your Own Exceptions........................................................................................................ 143
Issuing Warnings ........................................................................................................................... 143
Assertions and Debugging.............................................................................................................. 148
Context Managers.......................................................................................................................... 148
Summary ....................................................................................................................................... 150
■ Chapter 8: Modules and Packages for Code Reuse ...................................................................151
Imports for Reuse .......................................................................................................................... 151
Import Basics............................................................................................................................. 151
breakfast.py........................................................................................................................... 151
The Import Statement ................................................................................................................ 153
An Example Program...................................................................................................................... 153
greetings.py........................................................................................................................... 154
greet/__init__.py................................................................................................................... 154
greet/hello.py......................................................................................................................... 154
greet/people.py...................................................................................................................... 154
Trying Out the Example Code ..................................................................................................... 154
Types of Import Statements ........................................................................................................... 155
From Import Statements ............................................................................................................ 155
Relative Import Statements ........................................................................................................ 156
viii
www.it-ebooks.info
■ CONTENTS
Aliasing Import Statements ........................................................................................................ 156
Hiding Module Names................................................................................................................ 157
Module Search Path, Compilation, and Loading.............................................................................. 157
Java Import Example ................................................................................................................. 157
Module Search Path and Loading............................................................................................... 158
Java Package Scanning ................................................................................................................. 158
How Jython Finds the Jars and Classes to Scan......................................................................... 159
Compilation ............................................................................................................................... 160
Python Modules and Packages versus Java Packages.................................................................... 160
sys.path..................................................................................................................................... 160
Naming Python Modules and Packages...................................................................................... 160
Proper Python Naming ............................................................................................................... 161
Advanced Import Manipulation ....................................................................................................... 161
Import Hooks ............................................................................................................................. 161
sys.path_hooks.......................................................................................................................... 161
sys.meta_path ........................................................................................................................... 162
Summary ....................................................................................................................................... 162
Part II: Using the Language .............................................................................................................163
■ Chapter 9: Scripting With Jython ................................................................................................165
Getting the Arguments Passed to a Script ...................................................................................... 165
Searching for a File ........................................................................................................................ 166
Manipulating Files.......................................................................................................................... 167
Making a Script a Module .............................................................................................................. 168
Parsing Commandline Options ....................................................................................................... 169
Compiling Java Source................................................................................................................... 170
Example Script: Builder.py ............................................................................................................. 170
HelloWorld.java .............................................................................................................................. 172
Summary ....................................................................................................................................... 173
■ Chapter 10: Jython and Java Integration ...................................................................................175
Using Java Within Jython Applications ........................................................................................... 175
Using Jython Within Java Applications ........................................................................................... 178
Object Factories......................................................................................................................... 179
One-to-One Jython Object Factories ...................................................................................... 179
Summary of One-to-One Object Factory................................................................................. 182
ix
www.it-ebooks.info
■ CONTENTS
Making Use of a Loosely Coupled Object Factory ................................................................... 182
More Efficient Version of Loosely Coupled Object Factory....................................................... 186
Returning __doc__ Strings .................................................................................................... 188
Applying the Design to Different Object Types........................................................................ 190
JSR-223 .................................................................................................................................... 192
Utilizing PythonInterpreter .......................................................................................................... 193
Summary ....................................................................................................................................... 195
■ Chapter 11: Using Jython in an IDE ............................................................................................197
Eclipse........................................................................................................................................... 197
Installing PyDev ......................................................................................................................... 197
Minimal Configuration................................................................................................................ 198
Hello PyDev!: Creating Projects and Executing Modules ............................................................. 200
Passing Command-line Arguments and Customizing Execution.................................................. 201
Playing with the Editor ............................................................................................................... 202
A Bit of Structure: Packages, Modules, and Navigation............................................................... 204
Testing ...................................................................................................................................... 207
Adding Java Libraries to the Project ........................................................................................... 210
Debugging ..................................................................................................................................... 211
Conclusion about Eclipse ........................................................................................................... 213
Netbeans ....................................................................................................................................... 213
IDE Installation and Configuration................................................................................................... 214
Advanced Python Options............................................................................................................... 215
General Python Usage .................................................................................................................... 216
Standalone Jython Apps................................................................................................................. 216
Jython and Java Integrated Apps ................................................................................................... 221
Using a JAR or Java Project in Your Jython App ......................................................................... 221
Using Jython in Java.................................................................................................................. 222
The Netbeans Python Debugger ..................................................................................................... 223
Other Netbeans Python Features .................................................................................................... 228
Summary ....................................................................................................................................... 228
■ Chapter 12: Databases and Jython: Object Relational Mapping and Using JDBC ....................231
ZxJDBC—Using Python’s DB API via JDBC..................................................................................... 231
Getting Started........................................................................................................................... 232
Connections............................................................................................................................... 233
ZxJDBC.lookup .......................................................................................................................... 237
x
www.it-ebooks.info
■ CONTENTS
Cursors.................................................................................................................................. 237
Creating and Executing Queries ............................................................................................. 240
Prepared Statements ................................................................................................................. 243
Resource Management .............................................................................................................. 243
Metadata ................................................................................................................................... 244
Data Manipulation Language and Data Definition Language ....................................................... 245
Calling Procedures................................................................................................................. 246
Customizing zxJDBC Calls...................................................................................................... 247
History ....................................................................................................................................... 249
Object Relational Mapping.............................................................................................................. 249
SqlAlchemy................................................................................................................................ 249
Installation ................................................................................................................................. 249
Using SqlAlchemy ...................................................................................................................... 250
Hibernate................................................................................................................................... 254
Entity Classes and Hibernate Configuration ................................................................................ 254
Jython Implementation Using the Java Entity Classes................................................................. 256
Summary ....................................................................................................................................... 261
Part III: Developing Applications with Jython ................................................................................263
■ Chapter 13: Simple Web Applications ........................................................................................265
Servlets ......................................................................................................................................... 265
Configuring Your Web Application for Jython Servlets................................................................. 266
Writing a Simple Servlet............................................................................................................. 266
Using JSP with Jython ............................................................................................................... 268
Configuring for JSP................................................................................................................ 269
Coding the Controller/View..................................................................................................... 269
Applets and Java Web Start ........................................................................................................... 272
Coding a Simple GUI-Based Web Application.............................................................................. 272
Object Factory Application Design.......................................................................................... 272
Distributing via Standalone JAR ................................................................................................. 276
WSGI and Modjy............................................................................................................................. 276
Running a Modjy Application in Glassfish ................................................................................... 277
Summary ....................................................................................................................................... 280
■ Chapter 14: Web Applications With Django................................................................................281
Getting Django ............................................................................................................................... 281
xi
www.it-ebooks.info
■ CONTENTS
A Quick Tour of Django .................................................................................................................. 282
Starting a Project (and an “App”) ............................................................................................... 283
Models....................................................................................................................................... 284
Bonus: The Admin...................................................................................................................... 287
Views and Templates................................................................................................................. 292
Reusing Templates Without “include”: Template Inheritance...................................................... 297
Forms ........................................................................................................................................ 300
Feeds......................................................................................................................................... 302
Comments ................................................................................................................................. 304
And More................................................................................................................................... 306
J2EE Deployment and Integration................................................................................................... 307
Deploying Your First Application................................................................................................. 308
Disabling PostgreSQL Logins ..................................................................................................... 308
A Note About WAR Files ............................................................................................................. 309
Extended Installation.................................................................................................................. 311
Connection Pooling With JavaEE ................................................................................................ 312
Dealing With Long-running Tasks .............................................................................................. 315
Thread Pools.............................................................................................................................. 315
Passing Messages Across Process Boundaries........................................................................... 318
Summary ....................................................................................................................................... 325
■ Chapter 15: Introduction to Pylons .............................................................................................327
A Guide for the Impatient ............................................................................................................... 327
A Note about Paste ........................................................................................................................ 329
Pylons MVC.................................................................................................................................... 329
An Interlude into Java’s Memory Model.......................................................................................... 330
Invoking the Pylons Shell ............................................................................................................... 331
request.GET ............................................................................................................................... 332
request.POST............................................................................................................................. 332
request.params.......................................................................................................................... 332
request.headers......................................................................................................................... 333
Context Variables and Application Globals ...................................................................................... 333
Routes ........................................................................................................................................... 333
Controllers and Templates ............................................................................................................. 334
Adding a JSON API......................................................................................................................... 340
Unit Testing, Functional Testing, and Logging ................................................................................ 341
xii
www.it-ebooks.info
■ CONTENTS
Deployment into a Servlet Container .............................................................................................. 346
Summary ....................................................................................................................................... 346
■ Chapter 16: GUI Applications ......................................................................................................347
Summary ....................................................................................................................................... 357
■ Chapter 17: Deployment Targets ................................................................................................359
Application Servers ........................................................................................................................ 359
Tomcat ...................................................................................................................................... 360
Deploying Web Start .............................................................................................................. 360
Deploying a WAR or Exploded Directory Application ............................................................... 360
Glassfish.................................................................................................................................... 361
Deploying Web Start .............................................................................................................. 361
WAR File and Exploded Directory Deployment ........................................................................ 362
Glassfish v3 Django Deployment ............................................................................................ 362
Other Java Application Servers .................................................................................................. 362
Google App Engine......................................................................................................................... 362
Starting With an SDK Demo ....................................................................................................... 363
Deploying to the Cloud ............................................................................................................... 363
Working With a Project............................................................................................................... 364
Object Factories with App Engine ............................................................................................... 365
Using PyServlet Mapping ........................................................................................................... 365
Example Jython Servlet Application for App Engine .................................................................... 366
Using Eclipse ............................................................................................................................. 369
Deploy Modjy to GAE.................................................................................................................. 370
Java Store...................................................................................................................................... 370
Deploying a Single JAR .............................................................................................................. 371
Mobile............................................................................................................................................ 375
Summary ....................................................................................................................................... 375
Part IV: Strategy and Technique......................................................................................................377
■ Chapter 18: Testing and Continuous Integration .......................................................................379
Python Testing Tools...................................................................................................................... 379
UnitTest ..................................................................................................................................... 379
Doctests .................................................................................................................................... 384
A Complete Example.................................................................................................................. 388
Nose .......................................................................................................................................... 395
xiii
www.it-ebooks.info
■ CONTENTS
Integration with Java?................................................................................................................ 400
Continuous Integration ................................................................................................................... 401
Hudson ...................................................................................................................................... 401
Getting Hudson .......................................................................................................................... 401
Installing the Jython Plug-in....................................................................................................... 402
Creating a Hudson Job for a Jython Project................................................................................ 403
Using Nose on Hudson ............................................................................................................... 407
Summary ....................................................................................................................................... 410
■ Chapter 19: Concurrency.............................................................................................................413
Java or Python APIs?...................................................................................................................... 414
Working With Threads.................................................................................................................... 414
Thread Locals ................................................................................................................................ 416
No Global Interpreter Lock.............................................................................................................. 417
Module Import Lock ....................................................................................................................... 417
Working With Tasks ....................................................................................................................... 418
Thread Safety ................................................................................................................................ 422
Synchronization ......................................................................................................................... 423
Deadlocks.................................................................................................................................. 426
Other Synchronization Objects ................................................................................................... 427
Atomic Operations ..................................................................................................................... 431
Thread Confinement .................................................................................................................. 432
Python Memory Model ................................................................................................................... 433
Interruption .................................................................................................................................... 433
Summary ....................................................................................................................................... 436
■ Appendix A: Using Other Tools with Jython ...............................................................................437
The Jython Registry ....................................................................................................................... 437
Registry Properties..................................................................................................................... 437
python.cachedir ..................................................................................................................... 437
python.verbose ...................................................................................................................... 437
python.security.respectJavaAccessibility................................................................................ 438
python.jythonc.compiler......................................................................................................... 438
python.jythonc.classpath ....................................................................................................... 438
python.jythonc.compileropts .................................................................................................. 438
python.console ...................................................................................................................... 438
python.console.readlinelib ..................................................................................................... 438
xiv
www.it-ebooks.info
■ CONTENTS
Finding the Registry File............................................................................................................. 438
Setuptools...................................................................................................................................... 438
Virtualenv....................................................................................................................................... 442
■ Appendix B: Jython Cookbook ....................................................................................................445
Logging.......................................................................................................................................... 445
Using log4j with Jython, Josh Juneau ........................................................................................ 445
Setting Up Your Environment ................................................................................................. 445
Using log4j in a Jython Application......................................................................................... 446
Working with Spreadsheets............................................................................................................ 447
Creating and Reading Spreadsheets Using Apache Poi ............................................................... 447
Create Spreadsheet ............................................................................................................... 447
Read an Excel File.................................................................................................................. 449
Jython and XML ............................................................................................................................. 450
Writing and Parsing RSS with ROME, Josh Juneau..................................................................... 450
Setting up the CLASSPATH..................................................................................................... 450
Parsing Feeds ........................................................................................................................ 450
Creating Feeds....................................................................................................................... 451
Summary............................................................................................................................... 454
Working with CLASSPATH .............................................................................................................. 454
Using the CLASSPATH, Steve Langer.......................................................................................... 454
What to Do?........................................................................................................................... 454
Method .................................................................................................................................. 454
Summary............................................................................................................................... 456
Ant................................................................................................................................................. 456
Writing Ant Tasks with Jython, Ed Takema................................................................................. 456
Writing Custom Ant Tasks...................................................................................................... 457
Setup Development Environment ........................................................................................... 457
SimpleTask Jython Class ....................................................................................................... 457
Compiling Jython Code to a Jar.............................................................................................. 458
Build.XML File to Use the Task............................................................................................... 458
A Task Container Task ........................................................................................................... 458
Build.XML File to Use the TaskContainer ................................................................................ 459
Things to Look Out For........................................................................................................... 460
Summary............................................................................................................................... 461
Developing Django Web Apps......................................................................................................... 461
xv
www.it-ebooks.info
■ CONTENTS
Using Django in Netbeans, Josh Juneau..................................................................................... 461
■ Appendix C: Built-in Functions ...................................................................................................463
Constructor Functions .................................................................................................................... 463
bool([x]) ..................................................................................................................................... 463
chr(i).......................................................................................................................................... 463
complex([real[, imag]]) ............................................................................................................... 464
dict([arg])................................................................................................................................... 464
file(filename[, mode[, bufsize]]).................................................................................................. 464
float([x]) ..................................................................................................................................... 464
frozenset([iterable]).................................................................................................................... 464
int([x[, radix]]) ............................................................................................................................ 464
iter(o[, sentinel])......................................................................................................................... 465
list([iterable]).............................................................................................................................. 465
object() ...................................................................................................................................... 465
open(filename[, mode[, bufsize]]) ............................................................................................... 465
range([start,] stop[, step])........................................................................................................... 466
set([iterable]) ............................................................................................................................. 466
slice([start,] stop[, step]) ............................................................................................................ 466
str([object]) ................................................................................................................................ 467
tuple([iterable]) .......................................................................................................................... 467
type(name, bases, dict).............................................................................................................. 467
unichr(i) ..................................................................................................................................... 467
unicode([object[, encoding [, errors]]])........................................................................................ 467
xrange([start,] stop[, step])......................................................................................................... 468
Math Built-in Functions .................................................................................................................. 468
abs(x)......................................................................................................................................... 468
cmp(x, y).................................................................................................................................... 468
divmod(a, b)............................................................................................................................... 468
pow(x, y[, z]) .............................................................................................................................. 468
round(x[, n]) ............................................................................................................................... 469
Functions on Iterables.................................................................................................................... 469
all(iterable)................................................................................................................................. 469
any(iterable)............................................................................................................................... 469
enumerate(sequence[, start=0])................................................................................................. 469
filter(function, iterable)............................................................................................................... 469
xvi
www.it-ebooks.info
■ CONTENTS
map(function, iterable, ...) .......................................................................................................... 470
max(iterable[, key])or max([, arg, ...][, key])................................................................................ 470
min(iterable[, key]) or min([, arg, ...][, key]) ................................................................................ 470
reduce(function, iterable[, initializer]) ......................................................................................... 470
reversed(seq)............................................................................................................................. 470
sorted(iterable[, cmp[, key[, reverse]]])....................................................................................... 470
sum(iterable[, start=0]) .............................................................................................................. 471
zip([iterable, ...])......................................................................................................................... 471
Conversion Functions..................................................................................................................... 472
hex(x)......................................................................................................................................... 472
long([x[, radix]]).......................................................................................................................... 472
oct(x) ......................................................................................................................................... 472
ord(c)......................................................................................................................................... 472
Functions for Working with Code.................................................................................................... 472
classmethod(function)................................................................................................................ 472
compile(source, filename, mode[, flags[, dont_inherit]]) ............................................................. 473
eval(expression[, globals[, locals]])............................................................................................. 474
execfile(filename[, globals[, locals]]) .......................................................................................... 474
property([fget[, fset[, fdel[, doc]]]]) ............................................................................................. 475
staticmethod(function) ............................................................................................................... 476
super(type[, object-or-type]) ...................................................................................................... 476
Input Functions .............................................................................................................................. 477
input([prompt])........................................................................................................................... 477
raw_input([prompt])................................................................................................................... 477
Functions for Working with Modules and Objects ........................................................................... 478
callable(object)........................................................................................................................... 478
delattr(object, name).................................................................................................................. 478
dir([object]) ................................................................................................................................ 478
getattr(object, name[, default])................................................................................................... 479
globals()..................................................................................................................................... 479
hasattr(object, name) ................................................................................................................. 479
hash(object) ............................................................................................................................... 480
help([object]).............................................................................................................................. 480
id(object).................................................................................................................................... 480
isinstance(object, classinfo) ....................................................................................................... 480
xvii
www.it-ebooks.info
■ CONTENTS
issubclass(class, classinfo) ........................................................................................................ 480
len(s) ......................................................................................................................................... 480
locals()....................................................................................................................................... 481
reload(module)........................................................................................................................... 481
repr(object) ................................................................................................................................ 482
setattr(object, name, value)........................................................................................................ 482
type(object)................................................................................................................................ 482
vars([object]).............................................................................................................................. 482
__import__(name[, globals[, locals[, fromlist[, level]]]]).............................................................. 483
Index................................................................................................................................................485
xviii
www.it-ebooks.info
■
Foreword
I started using Python in 2003, and I fell in love with the language for a variety of reasons. The elegance
of Python’s whitespace based syntax, the well conceived built in data types, and a beautiful set of library
functions. Since that time, many other people have discovered or rediscovered Python. At the time of
this writing, the software industry is well into a resurgence of dynamically typed languages: Ruby, PHP,
and Python.
It wasn’t until I attended my first PyCon in 2004 that I became aware of Jython. People were glad of
the ability to run Python programs on the Java Virtual Machine (JVM), but were wistful because at the
time Jython was lagging behind the native C Python (CPython) interpreter in terms of supporting recent
versions of the language. Jython was maintained by a series of individual developers, but the task of
staying current with CPython was really too much for any single person. In December 2005, Frank
Wierzbicki took over as the lead developer for Jython, and over the next few years managed to foster a
community of developers for Jython. The authors of this book are some of the members of that
community. In June of 2009, the Jython community released Jython 2.5, which implemented the same
language as CPython 2.5. This was a major leap forward, bringing Jython much closer to feature parity
with CPython, and laying a foundation for catching up the rest of the way with CPython. Jython 2.5 is
able to run many of the most popular Python packages, including Django, Pylons, and SQLAlchemy.
Jython makes for a best of both worlds bridge between the elegant, expressive code of the Python
world and the “enterprise ready” Java world. Developers who work in organizations where Java is
already in use can now take advantage of the expressiveness and conciseness of Python by running their
Python programs on Jython. Jython provides easy integration and interoperability between Python code
and existing Java code.
Jython also has something to offer existing Python programmers, namely access to the very rich
ecosystem of the Java Virtual Machine. There is an enormous amount of Java code out in the world.
There are libraries for every task imaginable, and more. Jython gives Python programmers a way to tap
into these libraries, saving both development and testing time. Web applications running on Jython can
also take advantage of the scalability benefits of Java web containers such as Tomcat or GlassFish.
Things are looking very bright for Jython, and this book is a timely resource for people interested in
taking advantage of the benefits that Jython has to offer.
Ted Leung
xix
www.it-ebooks.info
■ CONTENTS
About the Authors
■ Josh Juneau has been a software developer since the mid-1990s. He graduated
from Northern Illinois University with a degree in Computer Science. His career
began as an Oracle database administrator which later led into PL/SQL
development and database programming. Josh began to use Java along with
PL/SQL for developing web applications, and later shifted to Java as a primary
base for application development. Josh has worked with Java in the form of web,
GUI, and command-line programming for several years. During his tenure as a
Java developer, he has worked with many frameworks including JSP, JSF, EJB, and
JBoss Seam. At the same time, Josh expanded his usage of the JVM by developing
applications with other JVM languages such as Jython and Groovy. Since 2006,
Josh has been the editor and publisher of the Jython Monthly newsletter. In late 2008, he began a podcast
dedicated to the Jython programming language. More modern releases of Jython have enabled Josh to
begin using it as one of the primary languages for his professional development. Currently, Josh spends
his days developing Java and Jython applications, and working with Oracle databases. When he is not
working, he enjoys spending time with his family. Josh also sneaks in enough time to maintain the
jython.org website, hack on the Jython language, and work on other such projects. He can be contacted
via his blog at http://www.jj-blogger.blogspot.com.
■ Jim Baker has over 15 years of software development experience, focusing on
business intelligence, enterprise application integration, and high-performance
web applications. He is a member of the Python Software Foundation and a
committer on Jython. Jim has presented at Devoxx, EuroPython, JavaOne, and the
Python Conference, as well as at numerous user groups. He is a graduate of both
Harvard and Brown.
■ Victor Ng has been slinging Python code in enterprises for 10 years and has worked in the banking,
adventure travel, and telecommunications industries. Victor attended the University of Waterloo where
he was busy learning to cook and didn’t attend too many classes. He lives just outside of Toronto,
Ontario, in Canada.
■ Leonardo Soto has been part of the Jython development team since the middle
of 2008, after he successfully completed a Google Summer of Code Project that
aimed to run and integrate the Django web framework with Jython. He is also
finishing his thesis to get the Informatics Engineering title from the Universidad
de Santiago de Chile and works on Continuum, a Chilean software boutique.
Leo has developed several software systems in the past seven years, most of
which are web applications, and based on the JavaEE (formerly J2EE) platform.
However, he has been spoiled by Python since the start of his professional
developer career, and he has missed its power and clarity countless times, which
inexorably turned him toward the Jython project.
xx
www.it-ebooks.info
■ ABOUT THE AUTHORS
■ Frank Wierzbicki is the head of the Jython project and a lead software
developer at Sauce Labs. He has been programming since the Commodore 64 was
the king of home computers (look it up, kids!) and can’t imagine why anyone
would do anything else for a living. Frank’s most enduring hobby is picking up
new programming languages, but he has yet to find one that is more fun to work
with than Python.
xxi
www.it-ebooks.info
■ CONTENTS
About the Technical Reviewers
■ Mark Ramm is project leader of TurboGears 2, and has written myriad
articles, and a book about TurboGears. He is a web developer at GeekNet
(geek.net) and is the founder of Compound Thinking (compoundthinking.com),
a consulting and development company focused on Python training, and web
application development.
■ Tobias Ivarsson is a software developer at Neo Technology, the commercial
backer of the open source graph database Neo4j (http://neo4j.org/). Tobias is
also a developer on the Jython project, with focus on the compiler.
xxii
www.it-ebooks.info
■ ACKNOWLEDGMENTS
Acknowledgments
First and foremost, I would like to thank my wife Angela for standing beside me throughout my career
and writing this book. She has been my inspiration and motivation for continuing to improve my
knowledge and move my career forward. She is my rock, and I dedicate this book to her. I also thank my
wonderful children: Katie, Jake, Matt, and our new addition Zachary, for always making me smile and for
understanding on those weekend mornings when I was writing this book instead of playing games. I
hope that one day they can read this book and understand why I spent so much time in front of my
computer.
I’d like to thank my parents and grandparents for allowing me to follow my ambitions throughout my
childhood. My family, including my in-laws, have always supported me throughout my career and
authoring this book and I really appreciate it. I look forward to discussing this book with my family at
future gatherings as I’m sure they will all read it soon.
My co-workers, especially Roger Slisz, Necota Smith, and Matt Arena, who showed me the ropes in
IT. Without that knowledge I wouldn’t have ventured into learning about Oracle and PL/SQL, which
ultimately led to this! I’d like to especially thank Roger Slisz and Kent Collins for trusting me to guide and
develop the applications for our department, and for allowing me the freedom to manage my projects
and provide the necessary time and resource toward our applications and databases.
I’d really like to thank Jim Baker for providing me with the opportunity to become the lead author for
this book. I appreciate that he believed in me to provide the leadership and knowledge to make this book
a reality. Jim Baker is a great person and a scholar; without him, this book may not have been written.
Jim and I collaborated to find the other great authors that helped us write this book. In the end, I
believe that the team of authors that was chosen provides the perfect blend of knowledge and skills that
went into authoring this book. I thank each of the authors for devoting their time and effort towards this
book; I think that it will be a great asset to the community! Thanks for everything, I look forward to
writing the second edition soon!
I owe a huge thanks to Duncan Parkes of Apress for providing excellent support and advice. I also
wish to thank all of our technical reviewers and our Apress project coordinator, Mary Tobin. All of their
efforts helped to make this book complete and we couldn’t have done it without you.
Last, but definitely not least, I’d like to thank the Jython developers and the community as a whole.
The developers work hard to provide us with this great technology allowing us to write Python on the
JVM. Frank Wierzbicki has done an excellent job in leading the core of Jython developers to produce
2.5.1, and I know that he’ll continue to do a great job leading into the future. Thanks to the community
for using Jython and providing great ideas and support via the mailing lists; without this help I could not
provide the newsletter and podcast.
Josh J. Juneau
This book is dedicated to my kids, Zack and Zoe, who are just about the best children a dad could hope
for: happy, loving, and fun to be with. Fundamentally, what I love to do is create, so it’s wonderful
watching you grow!
Three years ago, we had this audacious idea of reviving Jython. We would jump to supporting the 2.5
version of the Python language. And we would focus on making it a suitable platform for running the
increasingly large apps that are being developed. This meant a renewed focus on compatibility for
Jython. Fortunately, we could leverage the new reality that developers of Python applications,
xxiii
www.it-ebooks.info
■ ACKNOWLEDGMENTS
frameworks, and libraries increasingly have a commitment to strong testing. Our problem was tractable
because we could use this testing to converge on a robust implementation.
This book documents how we, in fact, achieved this goal, while still preserving the ability to
interactively explore and script the Java platform. In other words, Jython has grown up, but it hasn’t
forgotten what made it both useful and fun in the first place.
To my good friend Frank Wierzbicki, we made it happen; Charlie Nutter, for his commitment to
collaboration; Albert Wenger and Bruce Eckel, who both convinced me that working on Jython was
important; Leslie Hawthorn of the Google Open Source Programs Office; Dorene Beaver; Brian Goetz,
John Rose, and Ted Leung at Sun, for their support of alternative languages on the JVM; Chris Perkins,
Glyph Lefkowitz, Jacob Kaplan-Moss, Mark Ramm, and Raymond Hettinger for their support of a robust
Python ecosystem; my fellow Jython developers, Alan Kennedy, Charlie Groves, Josh Juneau, Nicholas
Riley, Oti Humbel, and Phil Jenvey, not to mention many other contributors. And especially to my
Google Summer of Code students, now also Jython committers, Leo Soto and Tobias Ivarsson: it’s been
wonderful watching you grow as both developers and individuals.
Jim Baker
Thanks to Liz and Rosie for putting up with far too many side projects this year. Special thanks to
everyone in the Jython and Python developer community for making life as a programmer much less
painful than it could be.
Victor Ng
First, thanks to my family for having patience with me when I took on yet another challenge which
decreases the amount of time I can spend with them. Especially Eliana, my mother, who has endured a
large part of that sacrifice, and also Nicolás, my brother, who gives encouragement in his own particular
way. They and Leocadio, my father, who rests in peace, forged my personality and share credit on every
goal I achieve.
Thanks to all my friends for sharing my happiness when starting this project and following with
encouragement when it seemed too difficult to be completed. I would have probably given up without
their support and example on what to do when you really want something.
Speaking of encouragement, I must mention that Jim Baker was responsible for having me on the
team who wrote this book: first by mentoring me on Jython and later by insisting that I should share part
of what I have learned on this book. He is a great person and I can only be grateful to have met him.
Thanks to Josh Juneau, our lead author. He coordinated our numerous team members and made
sure we all were on the right track. He did that while also working on a lot of chapters and also handling
the paperwork. I have no idea how he managed to do it. All I know is that he rocks.
Thanks to Duncan Parkes, our editor, and all the technical reviewers who worked on this book. Not
only by catching mistakes but also by suggesting those additions that can seem obvious in hindsight but
that would never have occurred to you.
On the first half of the Django chapter, I received a lot of help from Jacob Fenwick who discovered
some problems on specific platforms and offered valuable suggestions to overcome them. Thanks to
him, many readers won’t experience the frustration caused when the code shown on the book doesn’t
work on their environment. By the way, while working on Django integration with Jython, I’ve met a lot
of nice people in the Django community. Special thanks to Jacob Kaplan-Moss for his outstanding
support when I was working on that area.
And thanks to the Jython community! Starting with our leader, Frank Wierzbicki, who has played a
crucial role to move Jython forward in recent years. The core Jython developers are also really awesome
people and I’m immensely happy to work with them on the project. And every person of the Jython
community I’ve talked to has been nice and even when criticizing they know how to be constructive. I’m
grateful to work with this community and hope their members will find this book useful!
Leo Soto
xxiv
www.it-ebooks.info
■ ACKNOWLEDGMENTS
First and foremost, I want to thank my wife, Jill Fitzgibbons, for all of the support she has given through
all of these years of Jython work. Most of that work occurred on weekends, nights, while on vacation, and
other times inconvenient to my family. My daughter, Lily, who is five at the time of writing, has also
needed to show patience when her dad was working on Jython and on this book. I want to thank my
parents, who brought a Commodore 64 into the house when I was still impressionable enough to get
sucked into a life of programming. I also want to thank all of the contributors and users of Jython. They
make my work on Jython and this book worth doing.
Frank Wierzbicki
xxv
www.it-ebooks.info
■ ACKNOWLEDGMENTS
Introduction
Jython brings the power of the Python language to the JVM. It provides Java developers the ability to write
productive and dynamic code using an elegant syntax. Likewise, it allows Python developers to harness the
plethora of useful Java libraries and APIs that the JVM has to offer. We wrote this book in an effort to provide a
complete guide for developers from both parties. Whether you are a seasoned Java developer looking to add a
mature dynamic language to your arsenal, or a connoisseur of the Python language, this book provides useful
information in an easy-to-read fashion, which will help you become a professional Jython developer.
This book is organized so that each chapter is encapsulated as its own entity and can be read
separately from the others. This provides the ability to jump around the book if you’d like, or read it from
start to finish. Some chapters contain references to other parts of the book and this book builds upon
itself to guide a novice or a seasoned developer into becoming an expert Jython programmer. Since this
is a multi-author book, each of the chapters was written by an individual author or a pair of authors, and
because of this you may find that the chapters each contain a unique touch, but they are orchestrated in
such a way that they work very well together.
Part I of this book will take a look at the Python language and provide a tutorial to guide you through
learning the language from the ground up. It contains Python language basics, as well as Jython-specific
portions for those who already know Python. Until now, using Jython in Java applications has not been
very well documented. Part II addresses this topic, teaches you how to use Python and Java techniques
for working with databases, and even shows how to develop Jython using both the Eclipse and Netbeans
IDEs. The second part of the book is all about making use of Jython. Part III delves into developing full
applications with Jython, deploying them in different environments, and also testing them to ensure
stability. In this part, you’ll learn how to use the Django and Pylons web frameworks to develop
sophisticated web applications, and you’ll also learn how to develop robust desktop applications using
the Java Swing API along with Jython. Lastly, Part IV covers some concepts for making your application
development more productive, and ensuring that your Jython code is efficient. You’ll learn how to run
tests against your Jython code and set up continuous integration using Hudson. Advanced threading and
concurrency concepts are covered in Part IV to ensure that you have the knowledge to build Jython code
that performs well and runs efficiently. In the end, this book is great to read from start to finish, but also
very useful as a reference guide to using Jython with different technologies.
This book is available online under the Creative Commons Attribution Share-Alike license
(http://creativecommons.org/licenses/by-sa/3.0/). You can read the open source book at
http://jythonbook.com. I’d like to personally thank James Gardner, author of the Definitive Guide to
Pylons from Apress, for assisting us in transforming our book into restructured text format, which is used
to generate the Open Source online version.
Throughout the book, you will find a number of code examples. Many of the examples are Python
code; however, there are also plenty of Java examples as well as those working with web markup
languages. All code examples will be in the code font. The examples are available on the Apress website
at http://www.apress.com as well as at the Open Source site http://jythonbook.com.
This book will continue to evolve and we will continually update both the online version and the
printed copy. We’d like to thank members of the Jython community for contributing to the book,
especially Andrea Aime and others who wrote to the mailing lists providing comments and feedback for
book content. We would like to advocate that the community continues to stay involved with the book. If
you would like to post comments or suggestions for the book or if you find errors, please submit them
via apress.com.
xxvi
www.it-ebooks.info
■ INTRODUCTION
Thanks for reading this book, and for developing with the Jython language. We had a great time
working on this book and hope that you enjoy reading it just as much. We look forward to continually
updating this book, and seeing what the future will hold for Jython. Surely if Jython remains as active as
it is today, we will all enjoy it long into the future.
xxvii
www.it-ebooks.info
www.it-ebooks.info
C H A P T E R 10
■■■
P A R T
1
■■■
Jython Basics:
Learning the Language
1
www.it-ebooks.info
C H A P T E R 10
■■■
2
www.it-ebooks.info
CHAPTER 1
■■■
Language and Syntax
Elegant is an adjective that is often used to describe the Python language. The word elegant is defined as
“pleasingly graceful and stylish in appearance or manner.” Uncomplicated and powerful could also be
great words to assist in the description of this language. It is a fact that Python is an elegant language
that lets one create powerful applications in an uncomplicated manner. The ability to make reading and
writing complex software easier is the objective of all programming languages, and Python does just
that.
While we’ve easily defined the goal of programming languages in a broad sense in paragraph one,
we have left out one main advantage of learning the Python programming language: Python has been
extended to run on the Java platform, and so it can run anywhere with a JVM. There are also C and .NET
versions of Python with multiplatform support. So, Python can run nearly everywhere. In this book, we
focus on Jython, the language implementation that takes the elegance, power, and ease of Python and
runs it on the JVM.
The Java platform is an asset to the Jython language much like the C libraries are for Python. Jython
is able to run just about everywhere, which gives lots of flexibility when deciding how to implement an
application. Not only does the Java platform allow for flexibility with regards to application deployment,
but it also offers a vast library containing thousands of APIs that are available for use by Jython. Add in
the maturity of the Java platform and it becomes easy to see why Jython is such an attractive
programming language. The goal, if you will, of any programming language is to grant its developers the
same experience that Jython does. Simply put, learning Jython will be an asset to any developer.
As I’ve mentioned, the Jython language implementation takes Python and runs it on the JVM, but it
does much more than that. Once you have experienced the power of programming on the Java platform,
it will be difficult to move away from it. Learning Jython not only allows you to run on the JVM, but it
also allows you to learn a new way to harness the power of the platform. The language increases
productivity as it has an easily understood syntax that reads almost as if it were pseudocode. It also adds
dynamic abilities that are not available in the Java language itself.
In this chapter you will learn how to install and configure your environment, and you will also get an
overview of those features that the Python language has to offer. This chapter is not intended to delve so
deep into the concepts of syntax as to bore you, but rather to give you a quick and informative
introduction to the syntax so that you will know the basics and learn the language as you move on
through the book. It will also allow you the chance to compare some Java examples with those which are
written in Python so you can see some of the advantages this language has to offer.
By the time you have completed this chapter, you should know the basic structure and organization
that Python code should follow. You’ll know how to use basic language concepts such as defining
variables, using reserved words, and performing basic tasks. It will give you a taste of using statements
and expressions. As every great program contains comments, you’ll learn how to document single lines
of code as well as entire code blocks. As you move through the book, you will use this chapter as a
reference to the basics. This chapter will not cover each feature in completion, but it will give you
enough basic knowledge to start using the Python language.
3
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
The Difference between Jython and Python
Jython is an implementation of the Python language for the Java platform. Throughout this book, you
will be learning how to use the Python language, and along the way we will show you where the Jython
implementation differs from CPython, which is the canonical implementation of Python written in the C
language. It is important to note that the Python language syntax remains consistent throughout the
different implementations. At the time of this writing, there are three mainstream implementations of
Python. These implementations are: CPython, Jython for the Java platform, and IronPython for the .NET
platform. At the time of this writing, CPython is the most prevalent of the implementations. Therefore if
you see the word Python somewhere, it could well be referring to that implementation.
This book will reference the Python language in sections regarding the language syntax or
functionality that is inherent to the language itself. However, the book will reference the name Jython
when discussing functionality and techniques that are specific to the Java platform implementation. No
doubt about it, this book will go in-depth to cover the key features of Jython and you’ll learn concepts
that only adhere the Jython implementation. Along the way, you will learn how to program in Python
and advanced techniques.
Developers from all languages and backgrounds will benefit from this book. Whether you are
interested in learning Python for the first time or discovering Jython techniques and advanced concepts,
this book is a good fit. Java developers and those who are new to the Python language will find specific
interest in reading through Part I of this book as it will teach the Python language from the basics to
more advanced concepts. Seasoned Python developers will probably find more interest in Part II and
Part III as they focus more on the Jython implementation specifics. Often in this reference, you will see
Java code compared with Python code.
Installing and Configuring Jython
Before we delve into the basics of the language, we’ll learn how to obtain Jython and configure it for your
environment. To get started, you will need to obtain a copy of Jython from the official website
www.jython.org. Because this book focuses on release 2.5.x, it would be best to visit the site now and
download the most recent version of that release. You will see that there are previous releases that are
available to you, but they do not contain many of the features which have been included in the 2.5.x
series.
Jython implementation maintains consistent features which match those in the Python language for
each version. For example, if you download the Jython 2.2.1 release, it will include all of the features that
the Python 2.2 release contains. Similarly, when using the 2.5 release you will have access to the same
features which are included in Python 2.5. There are also some extra pieces included with the 2.5 release
which are specific to Jython. We’ll discuss more about these extra features throughout the book.
Please grab a copy of the most recent version of the Jython 2.5 release. You will see that the release is
packaged as a cross-platform executable JAR file. Right away, you can see the obvious advantage of
running on the Java platform. . .one installer that works for various platforms. It doesn’t get much easier
than that! In order to install the Jython language, you will need to have Java 5 or greater installed on your
machine. If you do not have Java 5 or greater then you’d better go and grab that from www.java.com and
install it before trying to initiate the Jython installer.
You can initiate the Jython installer by simply double-clicking on the JAR file. It will run you through
a series of standard installation questions. At one point you will need to determine which features you’d
like to install. If you are interested in looking through the source code for Jython, or possibly developing
code for the project then you should choose the “All” option to install everything. . .including source.
However, for most Jython developers and especially for those who are just beginning to learn the
language, I would recommend choosing the “Standard” installation option. Once you’ve chosen your
options and supplied an installation path then you will be off to the races.
In order to run Jython, you will need to invoke the jython.bat executable file on Windows or the
jython.sh file on *NIX machines and Mac OS X. That being said, you’ll have to traverse into the directory
4
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
that you’ve installed Jython where you will find the file. It would be best to place this directory within
your PATH environment variable on either Windows, *NIX, or OS X machines so that you can fire up
Jython from within any directory on your machine. Once you’ve done this then you should be able to
open up a terminal or command prompt and type “jython” then hit enter to invoke the interactive
interpreter. This is where our journey begins! The Jython interactive interpreter is a great place to
evaluate code and learn the language. It is a real-time testing environment that allows you to type code
and instantly see the result. As you are reading through this chapter, I recommend you open up the
Jython interpreter and follow along with the code examples.
Identifiers and Declaring Variables
Every programming language needs to contain the ability to capture or calculate values and store them.
Python is no exception, and doing so is quite easy. Defining variables in Python is very similar to other
languages such as Java, but there are a few differences that you need to note.
To define a variable in the Python language, you simply name it using an identifier. An identifier is a
name that is used to identify an object. The language treats the variable name as a label that points to a
value. It does not give any type for the value. Therefore, this allows any variable to hold any type of data.
It also allows the ability of having one variable contain of different data types throughout the life cycle of
a program. So a variable that is originally assigned with an integer, can later contain a String. Identifiers
in Python can consist of any ordering of letters, numbers, or underscores. However, an identifier must
always begin with a non-numeric character value. We can use identifiers to name any type of variable,
block, or object in Python. As with most other programming languages, once an identifier is defined, it
can be referenced elsewhere in the program.
Once declared, a variable is untyped and can take any value. This is one difference between using a
statically typed language such as Java, and using dynamic languages like Python. In Java, you need to
declare the type of variable which you are creating, and you do not in Python. It may not sound like very
much at first, but this ability can lead to some extraordinary results. Consider the following two listings,
lets define a value ‘x’ below and we’ll give it a value of zero.
Listing 1-1. Java – Declare Variable
int x = 0;
Listing 1-2. Python – Declare Variable
x = 0
As you see, we did not have to give a type to this variable. We simply choose a name and assign it a
value. Since we do not need to declare a type for the variable, we can change it to a different value and
type later in the program.
Listing 1-3.
x = 'Hello Jython'
We’ve just changed the value of the variable ‘x’ from a numeric value to a String without any
consequences. What really occurred is that we created a new variable ‘Hello Jython’ and assigned it to
the identifier ‘x’, which in turn lost its reference to 0. This is a key to the dynamic language philosophy. .
.change should not be difficult.
5
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
Let us take what we know so far and apply it to some simple calculations. Based upon the definition
of a variable in Python, we can assign an integer value to a variable, and change it to a float at a later
point. For instance:
Listing 1-4.
>>> x = 6
>>> y = 3.14
>>> x = x * y
>>> print x
18.84
In the previous example, we’ve demonstrated that we can dynamically change the type of any given
variable by simply performing a calculation upon it. In other languages such as Java, we would have had
to begin by assigning a float type to the ‘x’ variable so that we could later change its value to a float. Not
here, Python allows us to bypass type constriction and gives us an easy way to do it.
Reserved Words
There are a few more rules to creating identifiers that we must follow in order to adhere to the Python
language standard. Certain words are not to be used as identifiers as the Python language reserves them
for performing a specific role within our programs. These words which cannot be used are known as
reserved words. If we try to use one of these reserved words as an identifier, we will see a SyntaxError
thrown as Python wants these reserved words as its own.
There are no symbols allowed in identifiers. Yes, that means the Perl developers will have to get used
to defining variables without the $.
Table 1-1 lists all of the Python language reserved words:
Table 1-1. Reserved Words
and
assert
break
class
continue
def
del
elif
else
except
exec
finally
for
from
global
or
pass
print
raise
return
try
while
with
yield
It is important to take care when naming variables so that you do not choose a name that matches
one of the module names from the standard library.
Coding Structure
Another key factor in which Python differs from other languages is its coding structure. Back in the day,
we had to develop programs based upon a very strict structure such that certain pieces must begin and
6
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
end within certain punctuations. Python uses indentation rather than punctuation to define the
structure of code. Unlike languages such as Java that use brackets to open or close a code block, Python
uses spacing as to make code easier to read and also limit unnecessary symbols in your code. It strictly
enforces ordered and organized code but it lets the programmer define the rules for indentation,
although a standard of four characters exists.
For instance, let’s jump ahead and look at a simple ‘if’ statement. Although you may not yet be
familiar with this construct, I think you will agree that it is easy to determine the outcome. Take a look at
the following block of code written in Java first, and then we’ll compare it to the Python equivalent.
Listing 1-5. Java if-statement
x = 100;
if(x > 0){
System.out.println("Wow, this is Java");
} else {
System.out.println("Java likes curly braces");
}
Now, let’s look at a similar block of code written in Python.
Listing 1-6. Python if-statement
x = 100
if x > 0:
print 'Wow, this is elegant'
else:
print 'Organization is the key'
Okay, this is cheesy but we will go through it nonetheless as it is demonstrating a couple of key
points to the Python language. As you see, the Python program evaluates if the value of the variable ‘x’ is
greater than zero. If so, it will print ‘Wow, this is elegant.’ Otherwise, it will print ‘Organization is the
key.’ Look at the indentation which is used within the ‘if’ block. This particular block of code uses four
spaces to indent the ‘print’ statement from the initial line of the block. Likewise, the ‘else’ jumps back to
the first space of the line and its corresponding implementation is also indented by four spaces. This
technique must be adhered to throughout an entire Python application. By doing so, we gain a couple of
major benefits: easy-to-read code and no need to use curly braces. Most other programming languages
such as Java use a bracket “[” or curly brace “{” to open and close a block of code. There is no need to do
so when using Python as the spacing takes care of this for you. Less code = easier to read and maintain. It
is also worth noting that the Java code in the example could have been written on one line, or worse, but
we chose to format it nicely.
Python ensures that each block of code adheres to its defined spacing strategy in a consistent
manner. What is the defined spacing strategy? You decide. As long as the first line of a code block is outdented by at least one space, the rest of the block can maintain a consistent indentation, which makes
code easy to read. Many argue that it is the structuring technique that Python adheres to which makes
them so easy to read. No doubt, adhering to a standard spacing throughout an application makes for
organization. As mentioned previously, the Python standard spacing technique is to use four characters
for indentation. If you adhere to these standards then your code will be easy to read and maintain in the
future. Your brain seems hard-wired to adhering to some form of indentation, so Python and your brain
are wired up the same way.
7
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
Operators
The operators that are used by Python are very similar to those used in other languages...straightforward
and easy to use. As with any other language, you have your normal operators such as +, -, *, and /, which
are available for performing calculations. As you can see from the following examples, there is no special
trick to using any of these operators.
Listing 1-7. Performing Integer-based Operations
>>>
>>>
>>>
11
>>>
7
>>>
18
>>>
4
x = 9
y = 2
x + y
x - y
x * y
x / y
Perhaps the most important thing to note with calculations is that if you are performing calculations
based on integer values then you will receive a rounded result. If you are performing calculations based
upon floats then you will receive float results, and so on.
Listing 1-8. Performing Float-based Operations
>>> x
>>> y
>>> x
11.0
>>> x
7.0
>>> x
18.0
>>> x
4.5
= 9.0
= 2.0
+ y
- y
* y
/ y
It is important to note this distinction because as you can see from the differences in the results of
the division (/) operations in Listings 1-7 and 1-8, we have rounding on the integer values and not on the
float. A good rule of thumb is that if your application requires precise calculations to be defined, then it
is best to use float values for all of your numeric variables, or else you will run into a rounding issue. In
Python 2.5 and earlier, integer division always rounds down, producing the floor as the result. In Python
2.2, the // operator was introduced which is another way to obtain the floor result when dividing
integers or floats. This operator was introduced as a segue way for changing integer division in future
releases so that the result would be a true division. In Chapter 3, we’ll discuss division using a technique
that always performs true division.
Expressions
Expressions are just what they sound like. They are a piece of Python code that can be evaluated and
produces a value. Expressions are not instructions to the interpreter, but rather a combination of values
8
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
and operators that are evaluated. If we wish to perform a calculation based upon two variables or
numeric values then we are producing an expression.
Listing 1-9. Examples of Expressions
>>>
>>>
>>>
>>>
x
x
x
x
+
*
/
y
y
y
y
The examples of expressions that are shown above are very simplistic. Expressions can be made to
be very complex and perform powerful computations. They can be combined together to produce
complex results.
Functions
Oftentimes it is nice to take suites of code that perform specific tasks and extract them into their own
unit of functionality so that the code can be reused in numerous places without retyping each time. A
common way to define a reusable piece of code is to create a function. Functions are named portions of
code that perform that usually perform one or more tasks and return a value. In order to define a
function we use the def statement.
The def statement will become second nature for usage throughout any Python programmer’s life.
The def statement is used to define a function. Here is a simple piece of pseudocode that shows how to
use it.
Listing 1-10.
def my_function_name(parameter_list):
implementation
The pseudocode above demonstrates how one would use the def statement, and how to construct a
simple function. As you can see, def precedes the function name and parameter list when defining a
function.
Listing 1-11.
>>> def my_simple_function():
...
print 'This is a really basic function'
...
>>> my_simple_function()
This is a really basic function
This example is about the most basic form of function that can be created. As you can see, the
function contains one line of code which is a print statement. We will discuss the print statement in
more detail later in this chapter; however, all you need to know now is that it is used to print some text to
the screen. In this case, we print a simple message whenever the function is called.
Functions can accept parameters, or other program variables, that can be used within the context of
the function to perform some task and return a value.
9
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
Listing 1-12.
>>> def multiply_nums(x, y):
...
return x * y
...
>>> multiply_nums(25, 7)
175
As seen above, parameters are simply variables that are assigned when the function is called.
Specifically, we assign 25 to x and 7 to y in the example. The function then takes x and y, performs a
calculation and returns the result.
Functions in Python are just like other variables and they be passed around as parameters to other
functions if needed. Here we show a basic example of passing one function to another function. We’ll
pass the multiply_nums function into the function below and then use it to perform some calculations.
Listing 1-13.
>>> def perform_math(oper):
...
return oper(5, 6)
...
>>> perform_math(multiply_nums)
30
Although this example is very basic, you can see that another function can be passed as a parameter
and then used within another function. For more detail on using def and functions, please take a look at
Chapter 4, which is all about functions.
Classes
Python is an object-oriented programming language. which means that everything in the language is an
object of some type. Much like building blocks are used for constructing buildings, each object in Python
can be put together to build pieces of programs or entire programs. This section will give you a brief
introduction to Python classes, which are one of the keys to object orientation in this language.
Classes are defined using the class keyword. Classes can contain functions, methods, and variables.
Methods are just like functions in that the def keyword is used to create them, and they accept
parameters. The only difference is that methods take a parameter known as self that refers to the object
to which the method belongs. Classes contain what is known as an initializer method, and it is called
automatically when a class is instantiated. Let’s take a look at a simple example and then explain it.
10
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
Listing 1-14. Simple Python Class
>>> class my_object:
...
def __init__(self, x, y):
...
self.x = x
...
self.y = y
...
...
def mult(self):
...
print self.x * self.y
...
...
def add(self):
...
print self.x + self.y
...
>>> obj1 = my_object(7, 8)
>>> obj1.mult()
56
>>> obj1.add()
15
In this class example, we define a class named my_object. The class accepts two parameters, x and y.
A class initializer method is named __init__(), and it is used to initialize any values that may be used in
the class. An initializer also defines what values can be passed to a class in order to create an object. You
can see that each method and function within the class accepts the self argument. The self argument is
used to refer to the object itself, this is how the class shares variables and such. The self keyword is
similar to this in Java code. The x and y variables in the example are named self.x and self.y in the
initializer, that means that they will be available for use throughout the entire class. While working with
code within the object, you can refer to these variables as self.x and self.y. If you create the object and
assign a name to it such as obj1, then you can refer to these same variables as obj1.x and obj1.y.
As you can see, the class is called by passing the values 7 and 8 to it. These values are then assigned
to x and y within the class initializer method. We assign the class object to an identifier that we call obj1.
The obj1 identifier now holds a reference to my_object() with the values we’ve passed it. The obj1
identifier can now be used to call methods and functions that are defined within the class.
For more information on classes, please see Chapter 6, which covers object orientation in Python.
Classes are very powerful and the fundamental building blocks for making larger programs.
Statements
When we refer to statements, we are really referring to a line of code that contains an instruction that
does something. A statement tells the Python interpreter to perform a task. Ultimately, programs are
made up of a combination of expressions and statements. In this section, we will take a tour of statement
keywords and learn how they can be used.
Let’s start out by listing each of these different statement keywords, and then we will go into more
detail about how to use each of them with different examples. I will not cover every statement keyword
in this section as some of them are better left for later in the chapter or the book, but you should have a
good idea of how to code an action which performs a task after reading through this section. While this
section will provide implementation details about the different statements, you should refer to later
chapters to find advanced uses of these features.
11
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
Table 1-2. Statement Keywords
if-elif-else
for
while
continue
break
try-except-finally
assert
def
print
del
raise
import
Now that we’ve taken a look at each of these keywords, it is time to look at each of them in detail. It
is important to remember that you cannot use any of these keywords for variable names.
if-elif-else Statement
The if statement simply performs an evaluation on an expression and does different things depending
on whether it is True or False. If the expression evaluates to True then one set of statements will be
executed, and if it evaluates to False a different set of statements will be executed. If statements are quite
often used for branching code into one direction or another based upon certain values which have been
calculated or provided in the code.
Pseudocode would be as follows:
Listing 1-15.
if :
perform an action
else:
perform a different action
Any number of if/else statements can be linked together in order to create a logical code branch.
When there are multiple expressions to be evaluated in the same statement, then the elif statement can
be used to link these expressions together. Note that each set of statements within an if-elif-else
statement must be indented with the conditional statement out-dented and the resulting set of
statements indented. Remember, a consistent indentation must be followed throughout the course of
the program. The if statement is a good example of how well the consistent use of indention helps
readability of a program. If you are coding in Java for example, you can space the code however you’d
like as long as you use the curly braces to enclose the statement. This can lead to code that is very hard to
read…the indentation which Python requires really shines through here.
12
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
Listing 1-16. Example of if statement
>>> x = 3
>>> y = 2
>>> if x == y:
...
print 'x is equal to y'
... elif x > y:
...
print 'x is greater than y'
... else:
...
print 'x is less than y'
...
x is greater than y
While the code is simple, it demonstrates that using an if statement can result in branching code
logic.
print Statement
The print statement is used to display program output onto the screen (you’ve already seen it in action
several times). It can be used for displaying messages, which are printed from within a program, and also
for printing values, which may have been calculated. In order to display variable values within a print
statement, we need to learn how to use some of the formatting options that are available to Python. This
section will cover the basics of using the print statement along with how to display values by formatting
your strings of text.
In the Java language, we need to make a call to the System library in order to print something to the
command line. In Python, this can be done with the use of the print statement. The most basic use of the
print statement is to display a line of text. In order to do so, you simply enclose the text that you want to
display within single or double quotes. Take a look at the following example written in Java, and
compare it to the example immediately following which is rewritten in Python. I think you’ll see why the
print statement in Python makes life a bit easier.
Listing 1-17. Java Print Output Example
System.out.println("This text will be printed to the command line");
Listing 1-18. Python Print Output Example
print 'This text will be printed to the command line'
As you can see from this example, printing a line of text in Python is very straightforward. We can
also print variable values to the screen using the print statement.
Listing 1-19.
>>> my_value = 'I love programming in Jython'
>>> print my_value
I love programming in Jython
13
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
Once again, very straightforward in terms of printing values of variables. Simply place the variable
within a print statement. We can also use this technique in order to append the values of variables to a
line of text. In order to do so, just place the concatenation operator (+) in between the String of text
which you would like to append to, and the variable you’d like to append.
Listing 1-20.
>>> print 'I like programming in Java, but ' + my_value
I like programming in Java, but I love programming in Jython
This is great and all, but really not useful if you’d like to properly format your text or work with int
values. After all, the Python parser is treating the (+) operator as a concatenation operator in this
case...not as an addition operator. Python bases the result of the (+) operator on the type of the first
operand. If you try to append a numeric value to a String you will end up with an error.
Listing 1-21.
>>> z = 10
>>> print 'I am a fan of the number: ' + z
Traceback (most recent call last):
File "", line 1, in
TypeError: cannot concatenate 'str' and 'int' objects
As you can see from this example, Python does not like this trick very much. So in order to perform
this task correctly we will need to use some of the aforementioned Python formatting options. This is
easy and powerful to do, and it allows one to place any content or value into a print statement. Before
you see an example, let’s take a look at some of the formatting operators and how to choose the one that
you need.
•
%s - String
•
%d - Decimal
•
%f - Float
If you wish to include the contents of a variable or the result of an expression in your print
statement, you’ll use the following syntax:
Listing 1-22.
print 'String of text goes here %d %s %f' % (decimalValue, stringValue, floatValue)
In the pseudocode above (if we can really have pseudocode for print statements), we wish to print
the string of text, which is contained within the single quotes, but also have the values of the variables
contained where the formatting operators are located. Each of the formatting operators, which are
included in the string of text, will be replaced with the corresponding values from those variables at the
end of the print statement. The % symbol between the line of text and the list of variables tells Python
that it should expect the variables to follow, and that the value of these variables should be placed within
the string of text in their corresponding positions.
14
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
Listing 1-23.
>>> string_value = 'hello world'
>>> float_value = 3.998
>>> decimal_value = 5
>>> print 'Here is a test of the print statement using the values: %d, %s, and %f' %
(decimal_value, string_value, float_value)
Here is a test of the print statement using the values: 5, hello world, and 3.998000
As you can see this is quite easy to use and very flexible. The next example shows that we also have
the option of using expressions as opposed to variables within our statement.
Listing 1-24.
>>>
>>>
>>>
The
x = 1
y = 2
print 'The value of x + y is: %d' % (x + y)
value of x + y is: 3
The formatting operator that is used determines how the output looks, it does not matter what type
of input is passed to the operator. For instance, we could pass an integer or float to %s and it would print
just fine, but it will in effect be turned into a string in its exact format. If we pass an integer or float to %d
or %f, it will be formatted properly to represent a decimal or float respectively. Take a look at the
following example to see the output for each of the different formatting operators.
Listing 1-25.
>>> x = 2.3456
>>> print '%s' % x
2.3456
>>> print '%d' % x
2
>>> print '%f' % x
2.345600
Another useful feature of the print statement is that it can be used for debugging purposes. If we
simply need to find out the value of a variable during processing then it is easy to display using the print
statement. Using this technique can often really assist in debugging and writing your code.
try-except-finally
The try-except-finally is the supported method for performing error handling within a Python
application. The idea is that we try to run a piece of code and if it fails then it is caught and the error is
handled in a proper fashion. We all know that if someone is using a program that displays an ugly long
error message, it is not usually appreciated. Using the try-except-finally statement to properly catch and
handle our errors can mitigate an ugly program dump.
This approach is the same concept that is used within many languages, including Java. There are a
number of defined error types within the Python programming language and we can leverage these error
types in order to facilitate the try-except-finally process. When one of the defined error types is caught,
then a suite of code can be coded for handling the error, or can simply be logged, ignored, and so on.
15
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
The main idea is to avoid those ugly error messages and handle them neatly by displaying a formatted
error message or performing another process.
Listing 1-26.
>>> # Suppose we've calculated a value and assigned it to x
>>> x
8.97
>>> y = 0
>>> try:
...
print 'The rocket trajectory is: %f' % (x/y)
... except:
...
print 'Houston, we have a problem.
...
Houston, we have a problem.
If there is an exception that is caught within the block of code and we need a way to perform some
cleanup tasks, we would place the cleanup code within the finally clause of the block. All code within the
finally clause is always invoked before the exception is raised. The details of this topic can be read about
more in Chapter 7. In the next section, we’ll take a look at the raise statement, which we can use to raise
exceptions at any point in our program.
raise Statement
As mentioned in the previous section, the raise statement is used to throw or “raise” an exception in
Python. We know that a try-except clause is needed if Python decides to raise an exception, but what if
you’d like to raise an exception of your own? You can place a raise statement anywhere that you wish to
raise a specified exception. There are a number of defined exceptions within the language which can be
raised. For instance, NameError is raised when a specific piece of code is undefined or has no name. For
a complete list of exceptions in Python, please visit Chapter 7.
Listing 1-27.
>>> raise NameError
Traceback (most recent call last):
File "", line 1, in
NameError
If you wish to specify your own message within a raise then you can do so by raising a generic
Exception, and then specifying your message on the statement as follows.
Listing 1-28.
>>> raise Exception('Custom Exception')
Traceback (most recent call last):
File "", line 1, in
Exception: Custom Exception
16
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
import Statement
A program can be made up of one or more suites of code. In order to save a program so that it can be
used later, we place the code into files on our computer. Files that contain Python code should contain a
.py suffix such as my_code.py and so forth. These files are known as modules in the Python world. The
import statement is used much like it is in other languages, it brings external modules or code into a
program so that it can be used. This statement is ultimately responsible for reuse of code in multiple
locations. The import statement allows us to save code into a flat file or script, and then use it in an
application at a later time.
If a class is stored in an external module that is named the same as the class itself, the import
statement can be used to explicitly bring that class into an application. Similarly, if you wish to import
only a specific identifier from another module into your current module, then the specific code can be
named within using the syntax from <> import <>. Time to see some examples.
Listing 1-29.
# Import a module named TipCalculator
import TipCalculator
#
Import a function tipCalculator from within a module called ExternalModule.py
from ExternalModule import tipCalculator
When importing modules into your program, you must ensure that the module being imported does
not conflict with another name in your current program. To import a module that is named the same as
another identifier in your current program, you can use the as syntax. In the following example, let’s
assume that we have defined an external module with the name of tipCalculator.py and we want to use
it’s functionality in our current program. However, we already have a function named tipCalculator()
within the current program. Therefore, we use the as syntax to refer to the tipCalculator module.
Listing 1-30.
import tipCalculator as tip
This section just touches the surface of importing and working with external modules. For a more
detailed discussion, please visit Chapter 7 which covers this topic specifically.
Iteration
The Python language has several iteration structures which are used to traverse through a series of items
in a list, database records, or any other type of collection. A list in Python is a container that holds
objects or values and can be indexed. For instance, we create a list of numbers in the following example.
We then obtain the second element in the list by using the index value of 1 (indexing starts at zero, so the
first element of the list is my_numbers[0]).
17
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
Listing 1-31.
>>>
>>>
[1,
>>>
2
my_numbers = [1, 2, 3, 4, 5]
my_numbers
2, 3, 4, 5]
my_numbers[1]
For more information on lists, please see Chapter 2 that goes into detail about lists and other
containers that can be used in Python.
The most commonly used iteration structure within the language is probably the for loop, which is
known for its easy syntax and practical usage.
Listing 1-32.
>>> for value in my_numbers:
...
print value
...
1
2
3
4
5
However, the while loop still plays an important role in iteration, especially when you are not
dealing with collections of data, but rather working with conditional expressions. In this simple example,
we use a while loop to iterate over the contents of my_numbers. Note that the len() function just returns
the number of elements that are contained in the list.
Listing 1-33.
>>> x = 0
>>> while x < len(my_numbers):
...
print my_numbers[x]
...
x = x + 1
...
1
2
3
4
5
This section will take you though each of these two iteration structures and touch upon the basics of
using them. The while loop is relatively basic in usage, whereas there are many different
implementations and choices when using the for loop. I will only touch upon the for loop from a highlevel perspective in this introductory chapter, but if you wish to go more in-depth then please visit
Chapter 3.
18
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
While Loop
The while loop construct is used in order to iterate through code based upon a provided conditional
statement. As long as the condition is true, then the loop will continue to process. Once the condition
evaluates to false, the looping ends. The pseudocode for while loop logic reads as follows:
while True
perform operation
The loop begins with the declaration of the while and conditional expression, and it ends once the
conditional has been met and the expression is True. The expression is checked at the beginning of each
looping sequence, so normally some value that is contained within the expression is changed within the
suite of statements inside the loop. Eventually the value is changed in such a way that it makes the
expression evaluate to False, otherwise an infinite loop would occur. Keep in mind that we need to
indent each of the lines of code that exist within the while loop. This not only helps the code to maintain
readability, but it also allows Python to do away with the curly braces!
Listing 1-34. Example of a Java While Loop
int x = 9;
int y = 2;
int z = x – y;
while (y < x){
System.out.println("y is " + z + " less than x");
y = y++;
}
Now, let’s see the same code written in Python.
Listing 1-35. Example of a Python While Loop
>>> x = 9
>>> y = 2
>>> while y < x:
...
print 'y
...
y += 1
...
y is 7 less than
y is 6 less than
y is 5 less than
y is 4 less than
y is 3 less than
y is 2 less than
y is 1 less than
is %d less than x' % (x-y)
x
x
x
x
x
x
x
In this example, you can see that the conditional y < x is evaluated each time the loop passes. Along
the way, we increment the value of y by one each time we iterate, so that eventually y is no longer less
than x and the loop ends.
19
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
For Loop
We will lightly touch upon for loops in this chapter, but you can delve deeper into the topic in chapter
two or three when lists, dictionaries, tuples, and ranges are discussed. For now, you should know that a
for loop is used to iterate through a defined set of values. The for loop is very useful for performing
iteration through values because this is a concept which is used in just about any application. For
instance, if you retrieve a list of database values, you can use a for loop to iterate through them and print
each one out.
The pseudocode to for loop logic is as follows:
for each value in this defined set:
perform suite of operations
As you can see with the pseudocode, I’ve indented in a similar fashion to the way in which the other
expression constructs are indented. This uniform indentation practice is consistent throughout the
Python programming language. We’ll compare the for loop in Java to the Python syntax below so that
you can see how the latter makes code more concise.
Listing 1-36. Example of Java For Loop
for (x = 0; x <= 10; x++){
System.out.println(x);
}
Now, the same code implemented in Python:
Listing 1-37. Example of Python For Loop
>>> for x in range(10):
...
print x
...
0
1
2
3
4
5
6
7
8
9
In this example, we use a construct which has not yet been discussed. A range is a built-in function
for Python which simply provides a range from one particular value to another. In the example, we pass
the value 10 into the range which gives us all values between 0 and 10, inclusive of the zero at the front
and exclusive at the end. We see this in the resulting print out after the expression.
Basic Keyboard Input
The Python language has a couple of built-in functions to take input from the keyboard as to facilitate
the process of writing applications that allow user input. Namely, raw_input(), and input() can be used
20
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
to prompt and accept user input from the command-line. Not only is this useful for creating commandline applications and scripts, but it also comes in handy for writing small tests into your applications.
The raw_input() function accepts keyboard entry and converts it to a string, stripping the trailing
newline character. Similarly, the input() function accepts keyboard entry as raw_input(), but it then
evaluates it as an expression. The input() function should be used with caution as it expects a valid
Python expression to be entered. It will raise a SyntaxError if this is not the case. Using input() could
result in a security concern as it basically allows your user to run arbitrary Python code at will. It is best
to steer clear of using input() in most cases and just stick to using raw_input. Let’s take a look at using
each of these functions in some basic examples.
Listing 1-38. Using raw_input() and input()
# The text within the function is optional, and it is used as a prompt to the user
>>> name = raw_input("Enter Your Name:")
Enter Your Name:Josh
>>> print name
Josh
# Use the input function to evaluate an expression entered in by the user
>>> val = input ('Please provide an expression: ')
Please provide an expression: 9 * 3
>>> val
27
# The input function raises an error if an expression is not provided
>>> val = input ('Please provide an expression: ')
Please provide an expression: My Name is Josh
Traceback (most recent call last):
File "", line 1, in
File "", line 1
My Name is Josh
^
SyntaxError: invalid syntax
There will be examples provided later in the book for different ways of using the raw_input()
function. Now let’s take a look at some of the other Python statements that have not yet been covered in
this chapter.
Other Python Statements
There are some other Python statements that can be used within applications as well, but they are
probably better meant to be discussed within a later chapter as they provide more advanced
functionality. The following is a listing of other Python statements which you will read more about later
on:
exec—Execute Python code in a dynamic fashion
global—References a variable a global (Chapter 4)
with—New feature in 2.5 using __future__
class—Create or define a new class object (Chapter 6)
yield—Used with generators, returns a value (Chapter 4)
21
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
Documenting Code
Code documentation: an annoyingly important part of every application developer’s life. Although many
of us despise code documentation, it must exist for any application that is going to be used for
production purposes. Not only is proper code documentation a must for manageability and long-term
understanding of Python code fragments, but it also plays an important role in debugging some code as
we will see in some examples below.
Sometimes we wish to document an entire function or class, and other times we wish to document
only a line or two. Whatever the case, Python provides a way to do it in a rather unobtrusive manner.
Much like many of the other programming languages that exist today, we can begin a comment on any
part of any code line. We can also comment spanning multiple lines if we wish. Just on a personal note,
we rather like the Python documentation symbol (#) or hash, as it provides for clear-cut readability.
There are not many places in code that you will use the (#) symbol unless you are trying to perform some
documentation. Many other languages use symbols such as (/) which can make code harder to read as
those symbols are evident in many other non-documenting pieces of code. Okay, it is time to get off my
soap box on Python and get down to business.
In order to document a line of code, you simply start the document or comment with a (#) symbol.
This symbol can be placed anywhere on the line and whatever follows it is ignored by the Python
compiler and treated as a comment or documentation. Whatever precedes the symbol will be parsed as
expected.
Listing 1-39.
>>>
>>>
>>>
>>>
20
# This is a line of documentation
x = 0 # This is also documentation
y = 20
print x + y
As you can see, the Python parser ignores everything after the #, so we can easily document or
comment as needed.
One can easily document multiple lines of code using the # symbol as well by placing the hash at the
start of each line. It nicely marks a particular block as documentation. However, Python also provides a
multi-line comment using the triple-quote (‘‘‘) designation at the beginning and end of a comment. This
type of multi-line comment is also referred to as a doc string and it is only to be used at the start of a
module, class, or function. While string literals can be placed elsewhere in code, they will not be treated
as docstrings unless used at the start of the code. Let’s take a look at these two instances of multi-line
documentation in the examples that follow.
Listing 1-40. Multiple Lines of Documentation Beginning With #
# This function is used in order to provide the square
# of any value which is passed in. The result will be
# passed back to the calling code.
def square_val(value):
return value * value
...
>>> print square_val(3)
9
22
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
Listing 1-41. Multiple Lines of Documentation Enclosed in Triple Quotes (''')
def tip_calc(value, pct):
''' This function is used as a tip calculator based on a percentage
which is passed in as well as the value of the total amount. In
this function, the first parameter is to be the total amount of a
bill for which we will calculate the tip based upon the second
parameter as a percentage '''
return value * (pct * .01)
...
>>> print tip_calc(75,15)
11.25
Okay, as we can see, both of these documentation methods can be used to get the task of
documenting or comment code done. In Listing 1-40, we used multiple lines of documentation
beginning with the # symbol in order to document the square_val function. In Listing 1-41, we use the
triple-quote method in order to span multiple lines of documentation. Both of them appear to work as
defined. However, the second option provides a greater purpose as it allows one to document specific
named code blocks and retrieve that documentation by calling the help(function) function. For instance,
if we wish to find out what the square_val code does, we need to visit the code and either read the multiline comment or simply parse the code. However, if we wish to find out what the tip_calc function does,
we can call the help(tip_calc) function and the multi-line comment will be returned to us. This provides
a great tool to use for finding out what code does without actually visiting the code itself.
Listing 1-42. Printing the Documentation for the tip_calc Function
>>> help(tip_calc)
Help on function tip_calc in module __main__:
tip_calc(value, pct)
This function is used as a tip calculator based on a percentage
which is passed in as well as the value of the total amount. In
this function, the first parameter is to be the total amount of a
bill for which we will calculate the tip based upon the second
parameter as a percentage
These examples and short explanations should give you a pretty good feel for the power of
documentation that is provided by the Python language. As you can see, using the multi-line triplequote method is very suitable for documenting classes or functions. Commenting with the # symbol
provides a great way to organize comments within source and also for documenting those lines of code
which may be “not so easy” to understand.
Python Help
Getting help when using the Jython interpreter is quite easy. Built into the interactive interpreter is an
excellent help() option which provides information on any module, keyword, or topic available to the
Python language. By calling the help() function without passing in the name of a function, the Python
help system is invoked. While making use of the help() system, you can either use the interactive help
which is invoked within the interpreter by simply typing help(), or as we have seen previously you can
obtain the docstring for a specific object by typing help(object).
23
www.it-ebooks.info
CHAPTER 1 ■ LANGUAGE AND SYNTAX
It should be noted that while using the help system in the interactive mode, there is a plethora of
information available at your fingertips. If you would like to see for yourself, simply start the Jython
interactive interpreter and type help(). After you are inside the interactive help, you can exit at any time
by typing quit. In order to obtain a listing of modules, keywords, or topics you just type either “modules,”
“keywords,” or “topics”, and you will be provided with a complete listing. You will also receive help for
using the interactive help system. . .or maybe this should be referred to as meta-help!
Although the Jython interactive help system is great, you may still need further assistance. There are
a large number of books published on the Python language that will be sure to help you out. Make sure
that you are referencing a book that provides you with information for the specific Python release that
you are using as each version contains some differences. As mentioned previously in the chapter, the
Jython version number contains is consistent with its CPython counterpart. Therefore, each feature that
is available within CPython 2.5, for instance, should be available within Jython 2.5 and so on.
Summary
This chapter has covered lots of basic Python programming material. It should have provided a basic
foundation for the fundamentals of programming in Python. This chapter shall be used to reflect upon
while delving deeper into the language throughout the remainder of this book.
We began by discussing some of the differences between CPython and Jython. There are many good
reasons to run Python on the JVM, including the availability of great Java libraries and excellent
deployment targets. Once we learned how to install and configure Jython, we dove into the Python
language. We learned about the declaration of variables and explained the dynamic tendencies of the
language. We then went on to present the reserved words of the language and then discussed the coding
structure which must be adhered to when developing a Python application. After that, we discussed
operators and expressions. We learned that expressions are generally pieces of code that are evaluated to
produce a value. We took a brief tour of Python functions as to cover their basic syntax and usage.
Functions are a fundamental part of the language and most Python developers use functions in every
program. A short section introducing classes followed, it is important to know the basics of classes early
even though there is much more to learn in Chapter 6. We took a look at statements and learned that
they consist of instructions that allow us to perform different tasks within our applications. Each of the
Python statements were discussed and examples were given. Iteration constructs were then discussed so
that we could begin to use our statements and program looping tasks.
Following the language overview, we took a brief look at using keyboard input. This is a feature for
many programs, and it is important to know for building basic programs. We then learned a bit about
documentation, it is an important part of any application and Python makes it easy to do. Not only did
we learn how to document lines of code, but also documenting entire modules, functions and classes.
We touched briefly on the Python help() system as it can be a handy feature to use while learning the
language. It can also be useful for advanced programmers who need to look up a topic that they may be
a bit rusty on.
Throughout the rest of the book, you will learn more in-depth and advanced uses of the topics that
we’ve discussed in this chapter. You will also learn concepts and techniques that you’ll be able to utilize
in your own programs to make them more powerful and easy to maintain.
24
www.it-ebooks.info
CHAPTER 2
■■■
Data Types and Referencing
Programming languages and applications need data. We define applications to work with data, and we
need to have containers that can be used to hold it. This chapter is all about defining containers and
using them to work with application data. Whether the data we are using is coming from a keyboard
entry or if we are working with a database, there needs to be a way to temporarily store it in our
programs so that it can be manipulated and used. Once we're done working with the data then these
temporary containers can be destroyed in order to make room for new constructs.
We’ll start by taking a look at the different data types that are offered by the Python language, and
then we'll follow by discussing how to use that data once it has been collected and stored. We will
compare and contrast the different types of structures that we have in our arsenal, and we’ll give some
examples of which structures to use for working with different types of data. There are a multitude of
tasks that can be accomplished through the use of lists, dictionaries, and tuples and we will try to cover
many of them. Once you learn how to define and use these structures, then we’ll talk a bit about what
happens to them once they are no longer needed by our application.
Let’s begin our journey into exploring data types and structures within the Python programming
language. . .these are skills that you will use in each and every practical Jython program.
Python Data Types
As we’ve discussed, there is a need to store and manipulate data within programs. In order to do so then
we must also have the ability to create containers used to hold that data so that the program can use it.
The language needs to know how to handle data once it is stored, and we can do that by assigning data
type to our containers in Java. However, in Python it is not a requirement to do so because the
interpreter is able to determine which type of data we are storing in a dynamic fashion.
Table 2-1 lists each data type and gives a brief description of the characteristics that define each of
them.
Table 2-1. Python Data Types
Data Type
Characteristics
None
NULL value object
int
Plain integer (e.g., 32)
long
Long integer. Integer literal with an 'L' suffix, too long to be a plain integer
25
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Table 2-1. Python Data Types (continued)
Data Type
Characteristics
float
Floating-point number. Numeric literal containing decimal or exponent sign
complex
Complex number. Expressed as a sum of a numeric literal with a real and imaginary part
Boolean
True or False value (also characterized as numeric values of 1 and 0 respectively)
Sequence
Includes the following types: string, unicode string, basestring, list, tuple
Mapping
Includes the dictionary type
Set
Unordered collection of distinct objects; includes the following types: set, frozenset
File
Used to make use of file system objects
Iterator
Allows for iteration over a container. See section on Iterators for more details
Given all of that information and the example above, we should officially discuss how to declare a
variable in the Python language. Let’s take a look at some examples of defining variables in the following
lines of code.
Listing 2-1. Defining Variables in Jython
# Defining a String
x = 'Hello World'
x = "Hello World Two"
# Defining an integer
y = 10
# Float
z = 8.75
# Complex
i = 1 + 8.07j
An important point to note is that there really are no types in Jython. Every object is an instance of a
class. In order to find the type of an object, simply use the type() function.
Listing 2-2.
# Return the type of an object using the type function
>>> i = 1 + 8.07j
>>> type(i)
26
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
>>> a = 'Hello'
>>> type(a)
A nice feature to note is multiple assignment. Quite often it is necessary to assign a number of
values to different variables. Using multiple assignment in Python, it is possible to do this in one line.
Listing 2-3. Multiple Assignment
>>> x, y, z = 1, 2, 3
>>> print x
1
>>> print z
3
>>>
Strings and String Methods
Strings are a special type within most programming languages because they are often used to
manipulate data. A string in Python is a sequence of characters, which is immutable. An immutable
object is one that cannot be changed after it is created. The opposite would be a mutable object, which
can be altered after creation. This is very important to know as it has a large impact on the overall
understanding of strings. However, there are quite a few string methods that can be used to manipulate
the contents of a particular string. We never actually manipulate the contents though, these methods
return a manipulated copy of the string. The original string is left unchanged.
Prior to the release of Jython 2.5.0, CPython and Jython treated strings a bit differently. There are
two types of string objects in CPython, these are known as Standard strings and Unicode strings. There is
a lot of documentation available that specifically focuses on the differences between the two types of
strings, this reference will only cover the basics. It is worth noting that Python contains an abstract string
type known as basestring so that it is possible to check any type of string to ensure that it is a string
instance.
Prior to the release of Jython 2.5.0 there was only one string type. The string type in Jython
supported full two-byte Unicode characters and all functions contained in the string module were
Unicode-aware. If the u'' string modifier is specified, it is ignored by Jython. Since the release of 2.5.0,
strings in Jython are treated just like those in CPython, so the same rules will apply to both
implementations. If you are interested in learning more about String encoding, there are many great
references available on the topic. It is also worth noting that Jython uses character methods from the
Java platform. Therefore properties such as isupper and islower, which we will discuss later in the
section, are based upon the Java methods, although they actually work the same way as their CPython
counterparts
In the remainder of this section, we will go through each of the many string functions that are at our
disposal. These functions will work on both Standard and Unicode strings. As with many of the other
features in Python and other programming languages, at times there is more than one way to
accomplish a task. In the case of strings and string manipulation, this holds true. However, you will find
that in most cases, although there are more than one way to do things, Python experts have added
functions which allow us to achieve better performing and easier to read code.
Table 2-2 lists all of the string methods that have been built into the Python language as of the 2.5
release. Because Python is an evolving language, this list is sure to change in future releases. Most often,
additions to the language will be made, or existing features are enhanced. Following the table, we will
give numerous examples of the methods and how they are used. Although we cannot provide an
example of how each of these methods work (that would be a book in itself), they all function in the
same manner so it should be rather easy to pick up.
27
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Table 2-2. String Methods
Method
Description of Functionality
capitalize()
Returns a capitalized copy of string
center (width[,fill])
Returns a repositioned string with specified width and provide
optional padding filler character
count(sub[,start[,end]])
Count the number of distinct times the substring occurs within the
string
decode([encoding[,errors]])
Decodes and returns Unicode string
encode([encoding[,errors]])
Returns an encoded version of a string
endswith(suffix[,start[,end]])
Returns a boolean to state whether the string ends in a given pattern
expandtabs([tabsize])
Converts tabs within a string into spaces
find(sub[,start[,end]])
Returns the index of the position where the first occurrence of the
given substring begins
index(sub[,start[,end])
Returns the index of the position where the first occurrence of the
given substring begins. Raises a ValueError with the substring is not
found.
isalnum()
Returns a boolean to state whether the string contain only alphabetic
and numeric characters
isalpha()
Returns a boolean to state whether the string contains all alphabetic
characters
isdigit()
Returns a boolean to state whether the string contains all numeric
characters
islower()
Returns a boolean to state whether a string contains all lowercase
characters
isspace()
Returns a boolean to state whether the string consists of all whitespace
istitle()
Returns a boolean to state whether the first character of each word in
the string is capitalized
isupper()
Returns a boolean to state whether all characters within the string are
uppercase
28
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Table 2-2. String Methods (continued)
Method
Description of Functionality
join(sequence)
Returns a copy of sequence joined together with the original string
placed between each element
ljust(width[,fillchar])
Returns a string of the specified width along with a copy of the
original string at the leftmost bit. (Optionally padding empty space
with fillchar)
lower()
Returns a copy of the original string with all characters in the string
converted to lowercase
lstrip([chars])
Removes the first found characters in the string from the left that
match the given characters. Also removes whitespace from the left.
Whitespace removal is default when specified with no arguments.
partition(separator)
Returns a partitioned string starting from the left using the provided
separator
replace(old,new[,count])
Returns a copy of the original string replacing the portion of string
given in old with the portion given in new
rfind(sub[,start[,end]])
Searches string from right to left and finds the first occurrence of the
given string and returns highest index where sub is found
rindex(sub[,start[,end]])
Searches string from right to left and finds the first occurrence of the
given string and either returns highest index where sub is found or
raises an exception
rjust(width[,fillchar])
Returns copy of string Aligned to the right by width
rpartition(separator)
Returns a copy of stringPartitioned starting from the right using the
provided separator object
rsplit([separator[,maxsplit]])
Returns list of words in string and splits the string from the right side
and uses the given separator as a delimiter. If maxsplit is specified
then at most maxsplit splits are done (from the right).
rstrip([chars])
Returns copy of string removing the first found characters in the string
from the right that match those given. Also removes whitespace from
the right when no argument is specified.
split([separator[,maxsplit]])
Returns a list of words in string and splits the string from the left side
and uses the given separator as a delimiter.
29
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Table 2-2. String Methods (continued)
Method
Description of Functionality
splitlines([keepends])
Splits the string into a list of lines. Keepends denotes if newline
delimiters are removed. Returns the list of lines in the string.
startswith(prefix[,start[,end]])
Returns a boolean to state whether the string starts with the given
prefix
strip([chars])
Returns a copy of string with the given characters removed from the
string. If no argument is specified then whitespace is removed.
swapcase()
Returns a copy of the string the case of each character in the string
converted.
title()
Returns a copy of the string with the first character in each word
uppercase.
translate(table[,deletechars])
Returns a copy of the string using the given character translation table
to translate the string. All characters occurring in optional deletechars
argument are removed.
upper()
Returns a copy of string with all of the characters in the string
converted to uppercase
zfill(width)
Returns a numeric string padded from the left with zeros for the
specified width.
Now let’s take a look at some examples so that you get an idea of how to use the string methods. As
stated previously, most of them work in a similar manner.
Listing 2-4. Using String Methods
our_string='python is the best language ever'
# Capitalize first character of a String
>>> our_string.capitalize()
'Python is the best language ever'
# Center string
>>> our_string.center(50)
'
python is the best language ever
'
>>> our_string.center(50,'-')
'---------python is the best language ever---------'
# Count substring within a string
>>> our_string.count('a')
30
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
2
# Count occurrences of substrings
>>> state = 'Mississippi'
>>> state.count('ss')
2
# Partition a string returning a 3-tuple including the portion of string
# prior to separator, the separator
# and the portion of string after the separator
>>> x = "Hello, my name is Josh"
>>> x.partition('n')
('Hello, my ', 'n', 'ame is Josh')
# Assuming the same x as above, split the string using 'l' as the separator
>>> x.split('l')
['He', '', 'o, my name is Josh']
# As you can see, the tuple returned does not contain the separator value
# Now if we add maxsplits value of 1, you can see that the right-most split is
# taken. If we specify maxsplits value of 2, the two right-most splits are taken
>>> x.split('l',1)
['He', 'lo, my name is Josh']
>>> x.split('l',2)
['He', '', 'o, my name is Josh']
String Formatting
You have many options when printing strings using the print statement. Much like the C programming
language, Python string formatting allows you to make use of a number of different conversion types
when printing.
Listing 2-5. Using String Formatting
# The two syntaxes below work the same
>>> x = "Josh"
>>> print "My name is %s" % (x)
My name is Josh
>>> print "My name is %s" % x
My name is Josh
# An example using more than one argument
>>> name = 'Josh'
>>> language = 'Python'
>>> print "My name is %s and I speak %s" % (name, language)
My name is Josh and I speak Python
# And now for some fun, here's a different conversion type
# Mind you, I'm not sure where in the world the temperature would
# fluctuate so much!
>>> day1_temp = 65
>>> day2_temp = 68
31
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
>>> day3_temp = 84
>>> print "Given the temparatures %d, %d, and %d, the average would be %f" % (day1_temp,
day2_temp, day3_temp, (day1_temp + day2_temp + day3_temp)/3)
Given the temperatures 65, 68, and 83, the average would be 72.333333
Table 2-3 lists the conversion types.
Table 2-3. Conversion Types
Type
Description
d
signed integer decimal
i
signed integer
o
unsigned octal
u
unsigned decimal
x
unsigned hexidecimal (lowercase)
X
unsigned hexidecimal (uppercase letters)
E
floating point exponential format (uppercase 'E')
e
floating point exponential format (lowercase 'e')
f
floating point decimal format (lowercase)
F
floating point decimal format (same as 'f')
g
floating point exponential format if exponent < -4, otherwise float
G
floating point exponential format (uppercase) if exponent < -4, otherwise float
c
single character
r
string (converts any python object using repr())
s
string (converts any python object using str())
%
no conversion, results in a percent (%) character if specified twice
32
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Listing 2-6.
>>>
>>>
>>>
The
x = 10
y = 5.75
print 'The expression %d * %f results in %f' % (x, y, x*y)
expression 10 * 5.750000 results in 57.500000
# Example of using percentage
>>> test1 = 87
>>> test2 = 89
>>> test3 = 92
>>> "The gradepoint average of three students is %d%%" % (avg)
'The gradepoint average of three students is 89%'
Lists, Dictionaries, Sets, and Tuples
Lists, dictionaries, sets, and tuples all offer similar functionality and usability, but they each have their
own niche in the language. We’ll go through several examples of each since they all play an important
role under certain circumstances. Unlike strings, all of the containers discussed in this section (except
tuples) are mutable objects, so they can be manipulated after they have been created.
Because these containers are so important, we’ll go through an exercise at the end of this chapter,
which will give you a chance to try them out for yourself.
Lists
Perhaps one of the most used constructs within the Python programming language is the list. Most other
programming languages provide similar containers for storing and manipulating data within an
application. The Python list provides an advantage over those similar constructs that are available in
statically typed languages. The dynamic tendencies of the Python language help the list construct to
harness the great feature of having the ability to contain values of different types. This means that a list
can be used to store any Python data type, and these types can be mixed within a single list. In other
languages, this type of construct is often defined as a typed object, which locks the construct to using
only one data type.
The creation and usage of Python lists is just the same as the rest of the language. . .very simple and
easy to use. Simply assigning a set of empty square brackets to a variable creates an empty list. We can
also use the built-in list() function to create a list. The list can be constructed and modified as the
application runs, they are not declared with a static length. They are easy to traverse through the usage
of loops, and indexes can also be used for positional placement or removal of particular items in the list.
We’ll start out by showing some examples of defining lists, and then go through each of the different
avenues which the Python language provides us for working with lists.
Listing 2-7. Defining Lists
# Define an empty list
my_list = []
my_list = list() # rarely used
# Single Item List
>>> my_list = [1]
>>> my_list
>>> # interpreter
# note that there is no need to use print to display a variable in the
33
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
[1]
# Define a list of string values
my_string_list = ['Hello', 'Jython' ,'Lists']
# Define a list containing mulitple data types
multi_list = [1, 2, 'three', 4, 'five', 'six']
# Define a list containing a list
combo_list = [1, my_string_list, multi_list]
# Define a list containing a list inline
>>> my_new_list = ['new_item1', 'new_item2', [1, 2, 3, 4], 'new_item3']
>>> print my_new_list
['new_item1', 'new_item2', [1, 2, 3, 4], 'new_item3']
As stated previously, in order to obtain the values from a list we can make use of indexes. Much like
the Array in the Java language, using the list[index] notation will allow us to access an item. If we wish to
obtain a range or set of values from a list, we can provide a starting index, and/or an ending index. This
technique is also known as slicing. What’s more, we can also return a set of values from the list along
with a stepping pattern by providing a step index as well. One key to remember is that while accessing a
list via indexing, the first element in the list is contained within the 0 index. Note that when slicing a list,
a new list is always returned. One way to create a shallow copy of a list is to use slice notation without
specifying an upper or lower bound. The lower bound defaults to zero, and the upper bound defaults to
the length of the list.
Note that a shallow copy constructs a new compound object (list or other object containing objects)
and then inserts references into it to the original objects. A deep copy constructs a new compound
object and then inserts copies into it based upon the objects found in the original.
Listing 2-8. Accessing a List
# Obtain elements in the list
>>> my_string_list[0]
'Hello'
>>> my_string_list[2]
'Lists'
# Negative indexes start with the last element in the list and work back towards the first
# item
>>> my_string_list[-1]
'Lists'
>>> my_string_list[-2]
'Jython'
# Using slicing (Note that slice includes element at starting index and excludes the end)
>>> my_string_list[0:2]
['Hello', 'Jython']
# Create a shallow copy of a list using slice
>>> my_string_list_copy = my_string_list[:]
>>> my_string_list_copy
['Hello', 'Jython', 'Lists']
34
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
# Return every other element in a list
>>> new_list=[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# Using a third parameter in the slice will cause a stepping action to take place
# In this example we step by one
>>> new_list[0:10:1]
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# And here we step by two
>>> new_list[0:10:2]
[2, 6, 10, 14, 18]
# Leaving a positional index blank will also work as the default is 0 for the start, and the
length of the string for the end.
>>> new_list[::2]
[2, 6, 10, 14, 18]
Modifying a list is much the same, you can use the index in order to insert or remove items from a
particular position. There are also many other ways that you can insert or remove elements from the list.
Python provides each of these different options as they provide different functionality for your
operations.
Listing 2-9.
# Modify an element in a list. In this case we'll modify the element in the 9th position
>>> new_list[9] = 25
>>> new_list
[2, 4, 6, 8, 10, 12, 14, 16, 18, 25]
You can make use of the append() method in order to add an item to the end of a list. The extend()
method allows you to add copy of an entire list or sequence to the end of a list. Lastly, the insert()
method allows you to place an item or another list into a particular position of an existing list by utilizing
positional indexes. If another list is inserted into an existing list then it is not combined with the original
list, but rather it acts as a separate item contained within the original list. You will find examples of each
method below.
Similarly, we have plenty of options for removing items from a list. The del statement, as explained
in Chapter 1, can be used to remove or delete an entire list or values from a list using the index notation.
You can also use the pop() or remove() method to remove single values from a list. The pop() method will
remove a single value from the end of the list, and it will also return that value at the same time. If an
index is provided to the pop() function, then it will remove and return the value at that index. The
remove() method can be used to find and remove a particular value in the list. In other words, remove()
will delete the first matching element from the list. If more than one value in the list matches the value
passed into the remove() function, the first one will be removed. Another note about the remove()
function is that the value removed is not returned. Let’s take a look at these examples of modifying a list.
35
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Listing 2-10. Modifying a List
# Adding values to a list using the append method
>>> new_list=['a','b','c','d','e','f','g']
>>> new_list.append('h')
>>> print new_list
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
# Add another list to the existing list
>>> new_list2=['h','i','j','k','l','m','n','o','p']
>>> new_list.extend(new_list2)
>>> print new_list
['a', 'b', 'c', 'd', 'e', 'f', 'g', ‘h’,'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p']
# Insert a value into a particular location via the index.
# In this example, we add a 'c' into the third position in the list
# (Remember that list indicies start with 0, so the second index is actually the third
# position)
>>> new_list.insert(2,'c')
>>> print new_list
['a', 'b', 'c', 'c', 'd', 'e', 'f', 'g', 'h', ‘h’,'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p']
# Insert a list into a particular postion via the index
>>> another_list = ['a', 'b', 'c']
>>> another_list.insert(2, new_list)
>>> another_list
['a', 'b', [2, 4, 8, 10, 12, 14, 16, 18, 25], 'c']
# Use the slice notation to overwrite part of a list or sequence
>>> new_listA=[100,200,300,400]
>>> new_listB=[500,600,700,800]
>>> new_listA[0:2]=new_listB
>>> print new_listA
[500, 600, 700, 800, 300, 400]
# Assign a list to another list using the empty slice notation
>>> one = ['a', 'b', 'c', 'd']
>>> two = ['e', 'f']
>>> one
['a', 'b', 'c', 'd']
>>> two
['e', 'f']
# Obtain an empty slice from a list by using the same start and end position.
# Any start and end position will work, as long as they are the same number.
>>> one[2:2]
[]
# In itself, this is not very interesting – you could have made an empty list
# very easily. The useful thing about this is that you can assign to this empty slice
# Now, assign the 'two' list to an empty slice for the 'one' list which essentially
# inserts the 'two' list into the 'one' list
>>> one[2:2] = two
# the empty list between elements 1 and 2 of list 'one' is
>>>
# replaced by the list 'two'
36
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
>>> one
['a', 'b', 'c', 'd', 'e', 'f']
# Use the del statement to remove a value or range of values from a list
# Note that all other elements are shifted to fill the empty space
>>> new_list3=['a','b','c','d','e','f']
>>> del new_list3[2]
>>> new_list3
['a', 'b', 'd', 'e', 'f']
>>> del new_list3[1:3]
>>> new_list3
['a', 'e', 'f']
# Use the del statement to delete a list
>>> new_list3=[1,2,3,4,5]
>>> print new_list3
[1, 2, 3, 4, 5]
>>> del new_list3
>>> print new_list3
Traceback (most recent call last):
File "", line 1, in
NameError: name 'new_list3' is not defined
# Remove values from a list using pop and remove functions
>>> print new_list
['a', 'b', 'c', 'c', 'd', 'e', 'f', 'g', 'h',’h’, 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p']
# pop the element at index 2
>>> new_list.pop(2)
'c'
>>> print new_list
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',’h’, 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p']
# Remove the first occurrence of the letter 'h' from the list
>>> new_list.remove('h')
>>> print new_list
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p']
# Useful example of using pop() function
>>> x = 5
>>> times_list = [1,2,3,4,5]
>>> while times_list:
...
print x * times_list.pop(0)
...
5
10
15
20
25
Now that we know how to add and remove items from a list, it is time to learn how to manipulate
the data within them. Python provides a number of different methods that can be used to help us
manage our lists. See Table 2-4 for a list of these functions and what they can do.
37
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Table 2-4. Python List Methods
Method
Tasks Performed
index
Returns the index of the first value in the list which matches a given value.
count
Returns the number of items in the list which equal a given value.
sort
Sorts the items contained within the list and returns the list
reverse
Reverses the order of the items contained within the list, and returns the list
Let’s take a look at some examples of how these functions can be used on lists.
Listing 2-11. Utilizing List Functions
# Returning the index for any given value
>>> new_list=[1,2,3,4,5,6,7,8,9,10]
>>> new_list.index(4)
3
# Change the value of the element at index 4
>>> new_list[4] = 30
>>> new_list
[1, 2, 3, 4, 30, 6, 7, 8, 9, 10]
# Ok, let's change it back
>>> new_list[4] = 5
>>> new_list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Add a duplicate value into the list and then return the index
# Note that index returns the index of the first matching value it encounters
>>> new_list.append(6)
>>> new_list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 6]
>>> new_list.index(6)
5
# Using count() function to return the number of items which
>>> new_list.count(2)
1
>>> new_list.count(6)
2
# Sort the values in the list
>>> new_list.sort()
>>> new_list
[1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 10]
# Reverse the order of the value in the list
38
www.it-ebooks.info
equal a given value
CHAPTER 2 ■ DATA TYPES AND REFERNCING
>>> new_list.reverse()
>>> new_list
[10, 9, 8, 7, 6, 6, 5, 4, 3, 2, 1]
Traversing and Searching Lists
Moving around within a list is quite simple. Once a list is populated, often times we wish to traverse
through it and perform some action against each element contained within it. You can use any of the
Python looping constructs to traverse through each element within a list. While there are plenty of
options available, the for loop works especially well. This is because of the simple syntax that the Python
for loop uses. This section will show you how to traverse a list using each of the different Python looping
constructs. You will see that each of them has advantages and disadvantages.
Let’s first take a look at the syntax that is used to traverse a list using a for loop. This is by far one of
the easiest modes of going through each of the values contained within a list. The for loop traverses the
list one element at a time, allowing the developer to perform some action on each element if so desired.
Listing 2-12. Traversing a List Using a ‘for’ Loop
>>> ourList=[1,2,3,4,5,6,7,8,9,10]
>>> for elem in ourList:
...
print elem
...
1
2
3
4
5
6
7
8
9
10
As you can see from this simple example, it is quite easy to go through a list and work with each item
individually. The for loop syntax requires a variable to which each element in the list will be assigned for
each pass of the loop.
It is also possible to combine slicing with the use of the for loop. In this case, we’ll simply use a list
slice to retrieve the exact elements we want to see. For instance, take a look a the following code which
traverses through the first 5 elements in our list.
Listing 2-13.
>>> for elem in ourList[:5]:
...
print elem
...
1
2
3
4
5
As you can see, doing so is quite easy by simply making use of the built-in features that Python
offers.
39
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
List Comprehensions
As we've seen in the previous section, we can create a copy of a list using the slicing. Another more
powerful way to do so is via the list comprehension. There are some advanced features for lists that can
help to make a developer’s life easier. One such feature is known as a list comprehension. While this
concept may be daunting at first, it offers a good alternative to creating many separate lists manually.
List comprehensions take a given list, and then iterate through it and apply a given expression against
each of the objects in the list.
Listing 2-14. Simple List Comprehension
# Multiply each number in a list by 2 using a list comprehension
# Note that list comprehension returns a new list
>>> num_list = [1, 2, 3, 4]
>>> [num * 2 for num in num_list]
[2, 4, 6, 8]
# We could assign a list comprehension to a variable
>>> num_list2 = [num * 2 for num in num_list]
>>> num_list2
[2, 4, 6, 8]
As you can see, this allows one to quickly take a list and alter it via the use of the provided
expression. Of course, as with many other Python methods the list comprehension returns an altered
copy of the list. The list comprehension produces a new list and the original list is left untouched.
Let’s take a look at the syntax for a list comprehension. They are basically comprised of an expression of
some kind followed by a for statement and then optionally more for or if statements. The basic
functionality of a list comprehension is to iterate over the items of a list, and then apply some expression
against each of the list’s members. Syntactically, a list comprehension reads as follows:
Iterate through a list and optionally perform an expression on each element, then either
return a new list containing the resulting elements or evaluate each element given an
optional clause.
[list-element (optional expression) for list-element in list (optional clause)]
Listing 2-15. Using an If Clause in a List Comprehension
# The following example returns each element
# in the list that is greater than the number 4
>>> nums = [2, 4, 6, 8]
>>> [num for num in nums if num > 4]
[6, 8]
Let’s take a look at some more examples. Once you’ve seen list comprehensions in action you are
sure to understand them and see how useful they can be.
Listing 2-16. Python List Comprehensions
# Create a list of ages and add one to each of those ages using a list comprehension
>>> ages=[20,25,28,30]
>>> [age+1 for age in ages]
[21, 26, 29, 31]
40
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
# Create a list of names and convert the first letter of each name to uppercase as it should
be
>>> names=['jim','frank','vic','leo','josh']
>>> [name.title() for name in names]
['Jim', 'Frank', 'Vic', 'Leo', 'Josh']
# Create a list of numbers and return the square of each EVEN number
>>> numList=[1,2,3,4,5,6,7,8,9,10,11,12]
>>> [num*num for num in numList if num % 2 == 0]
[4, 16, 36, 64, 100, 144]
# Use a list comprehension with a range
>>> [x*5 for x in range(1,20)]
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
# Use a for clause to perform calculations against elements of two different lists
>>> list1 = [5, 10, 15]
>>> list2 = [2, 4, 6]
>>> [e1 + e2 for e1 in list1 for e2 in list2]
[7, 9, 11, 12, 14, 16, 17, 19, 21]
List comprehensions can make code much more concise and allows one to apply expressions or
functions to list elements quite easily. Let’s take a quick look at an example written in Java for
performing the same type of work as an list comprehension. It is plain to see that list comprehensions
are much more concise.
Listing 2-17. Java Code to Take a List of Ages and Add One Year to Each Age
int[] ages = {20, 25, 28, 30};
int[] ages2 = new int[ages.length];
// Use a Java for loop to go through each element in the array
for (int x = 0; x <= ages.length; x++){
;
ages2[x] = ages[x]+1;
}
Tuples
Tuples are much like lists; however, they are immutable. Once a tuple has been defined, it cannot be
changed. They contain indexes just like lists, but again, they cannot be altered once defined. Therefore,
the index in a tuple may be used to retrieve a particular value and not to assign or modify. While tuples
may appear similar to lists, they are quite different in that tuples usually contain heterogeneous
elements, whereas lists oftentimes contain elements that are related in some way. For instance, a
common use case for tuples is to pass parameters to a function, method, and so on.
Since tuples are a member of the sequence type, they can use the same set of methods an
operations available to all sequence types.
41
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Listing 2-18. Examples of Tuples
# Creating an empty tuple
>>> myTuple = ()
# Creating tuples and using them
>>> myTuple2 = (1, 'two',3, 'four')
>>> myTuple2
(1, 'two', 3, 'four')
# To create a single-item tuple, include a trailing comma
>>> myteam = 'Bears',
>>> myteam
('Bears',)
As mentioned previously, tuples can be quite useful for passing to functions, methods, classes, and
so on. Oftentimes, it is nice to have an immutable object for passing multiple values. One such case
would be using a tuple to pass coordinates in a geographical information system or another application
of the kind. They are also nice to use in situations where an immutable object is warranted. Because they
are immutable, their size does not grow once they have been defined, so tuples can also play an
important role when memory allocation is a concern.
Dictionaries
A Python dictionary is a key-value store container. A dictionary is quite different than a typical list in
Python as there is no automatically populated index for any given element within the dictionary. When
you use a list, you need not worry about assigning an index to any value that is placed within it. A
dictionary allows the developer to assign an index or “key” for every element that is placed into the
construct. Therefore, each entry into a dictionary requires two values, the key and the element.
The beauty of the dictionary is that it allows the developer to choose the data type of the key value.
Therefore, if one wishes to use a string or any other hashable object such as an int or float value as a key
then it is entirely possible. Dictionaries also have a multitude of methods and operations that can be
applied to them to make them easier to work with. Table 2-5 lists dictionary methods and functions.
Listing 2-19. Basic Dictionary Examples
# Create an empty dictionary and a populated dictionary
>>> myDict={}
>>> myDict.values()
[]
# Assign key-value pairs to dictionary
>>> myDict['one'] = 'first'
>>> myDict['two'] = 'second'
>>> myDict
{'two': 'second', 'one': 'first'}
42
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Table 2-5. Dictionary Methods and Functions
Method or Function
Description
len(dictionary)
Function that returns number of items within the given dictionary.
dictionary [key]
Returns the item from the dictionary that is associated with the given
key.
dictionary[key] = value
Sets the associated item in the dictionary to the given value.
del dictionary[key]
Deletes the given key/value pair from the dictionary.
dictionary.clear()
Method that removes all items from the dictionary.
dictionary.copy()
Method that creates a shallow copy of the dictionary.
has_key(key)
Function that returns a boolean stating whether the dictionary contains
the given key. (Deprecated in favor of using in')
key in d
Returns a boolean stating whether the given key is found in the
dictionary
key not in d
Returns a boolean stating whether the given key is not found in the
dictionary
items()
Returns a list of tuples including a copy of the key/value pairs within the
dictionary.
keys()
Returns the a list of keys within the dictionary.
update([dictionary2])
Updates dictionary with the key/value pairs from the given dictionary.
Existing keys will be overwritten.
fromkeys(sequence[,value])
Creates a new dictionary with keys from the given sequence. The values
will be set to the value given.
values()
Returns the values within the dictionary as a list.
get(key[, b])
Returns the value associated with the given key. If the key does not exist,
then returns b.
setdefault(key[, b])
Returns the value associated with the given key. If the key does not exist,
then the key value is set to b (mydict[key] = b)
pop(key[, b])
Returns and removes the key/value pair associated with the given key. If
the key does not exist then returns b.
43
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Table 2-5. Dictionary Methods and Functions (continued)
Method or Function
Description
popItem()
An arbitrary key/value pair is popped from the dictionary
iteritems()
Returns an iterator over the key/value pairs in the dictionary.
iterkeys()
Returns an iterator over the keys in the dictionary.
itervalues()
Returns an iterator over the values in the dictionary.
Now we will take a look at some dictionary examples. This reference will not show you an example
of using each of the dictionary methods and functions, but it should provide you with a good enough
base understanding of how they work.
Listing 2-20. Working with Python Dictionaries
# Create an empty dictionary and a populated dictionary
>>> mydict = {}
# Try to find a key in the dictionary
>>> 'firstkey' in mydict
False
# Add key/value pair to dictionary
>>> mydict['firstkey'] = 'firstval'
>>> 'firstkey' in mydict
True
# List the values in the dictionary
>>> mydict.values()
['firstval']
# List the keys in the dictionary
>>> mydict.keys()
['firstkey']
# Display the length of the dictionary (how many
>>> len(mydict)
1
key/value pairs are in it)
# Print the contents of the dictionary
>>> mydict
{'firstkey': 'firstval'}
>>>
# Replace the original dictionary with a dictionary containing string-based keys
# The following dictionary represents a hockey team line
44
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
>>> myDict =
{'r_wing':'Josh','l_wing':'Frank','center':'Jim','l_defense':'Leo','r_defense':'Vic'}
>>> myDict.values()
['Josh', 'Vic', 'Jim', 'Frank', 'Leo']
>>> myDict.get('r_wing')
'Josh'
>>> myDict['r_wing']
'Josh'
# Try to obtain the value for a key that does not exist
>>> myDict['goalie']
Traceback (most recent call last):
File "", line 1, in
KeyError: 'goalie'
# Try to obtain a value for a key that does not exist using get()
>>> myDict.get('goalie')
# Now use a default message that will be displayed if the key does not exist
>>> myDict.get('goalie','Invalid Position')
'Invalid Position'
# Iterate over the items in the dictionary
>>> for player in myDict.iterItems():
...
print player
...
('r_wing', 'Josh')
('r_defense', 'Vic')
('center', 'Jim')
('l_wing', 'Frank')
('l_defense', 'Leo')
# Assign keys and values to separate objects and then print
>>> for key,value in myDict.iteritems():
...
print key, value
...
r_wing Josh
r_defense Vic
center Jim
l_wing Frank
l_defense Leo
Sets
Sets are unordered collections of unique elements. What makes sets different than other sequence types
is that they contain no indexing or duplicates. They are also unlike dictionaries because there are no key
values associated with the elements. They are an arbitrary collection of unique elements. Sets cannot
contain mutable objects, but sets themselves can be mutable. Another thing to note is that sets are note
available to use by default, you must import set from the Sets module before using.
45
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Listing 2-21. Examples of Sets
# In order to use a Set, we must first import it
>>> from sets import Set
# To create a set use the following syntax
>>> myset = Set([1,2,3,4,5])
>>> myset
Set([5, 3, 2, 1, 4])
# Add a value to the set – See Table 2-7 for more details
>>> myset.add(6)
>>> myset
Set([6, 5, 3, 2, 1, 4])
# Try to add a duplicate
>>> myset.add(4)
>>> myset
Set([6, 5, 3, 2, 1, 4])
There are two different types of sets, namely set and frozenset. The difference between the two is
quite easily conveyed from the name itself. A regular set is a mutable collection object, whereas a frozen
set is immutable. Remember, immutable objects cannot be altered once they have been created whereas
mutable objects can be altered after creation. Much like sequences and mapping types, sets have an
assortment of methods and operations that can be used on them. Many of the operations and methods
work on both mutable and immutable sets. However, there are a number of them that only work on the
mutable set types. In Tables 2-6 and 2-7, we’ll take a look at the different methods and operations.
Table 2-6. Set Type Methods and Functions
Method or Operation
Description
len(set)
Returns the number of elements in a given set
copy()
Returns a new shallow copy of the set
difference(set2)
Returns a new set that contains all elements that are in the calling set,
but not in set2
intersection(set2)
Returns a new set that contains all elements that the calling set and set2
have in common
issubbset(set2)
Returns a Boolean stating whether all elements in calling set are also in
set2
issuperset(set2)
Returns a Boolean stating whether all elements in set2 are contained in
calling set
symmetric_difference(set2)
Returns a new set containing elements either from the calling set or set2
but not from both (set1 ^ set2)
46
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Table 2-6. Set Type Methods and Functions (continued)
Method or Operation
Description
x in set
Tests whether x is contained in the set, returns boolean
x not in set
Tests whether x is not contained in the set, returns boolean
union(set2)
Returns a new set containing elements that are contained in both the calling
set and set2
Listing 2-22. Using Set Type Methods and Functions
# Create two sets
>>> s1 = Set(['jython','cpython','ironpython'])
>>> s2 = Set(['jython','ironpython','pypy'])
# Make a copy of a set
>>> s3 = s1.copy()
>>> s3
Set(['cpython', 'jython', 'ironpython'])
# Obtain a new set containing all elements that are in s1 but not s2
>>> s1.difference(s2)
Set(['cpython'])
# Obtain a new set containing all elements from each set
>>> s1.union(s2)
Set(['cpython', 'pypy', 'jython', 'ironpython'])
# Obtain a new set containing elements from either set that are not contained in both
>>> s1.symmetric_difference(s2)
Set(['cpython', 'pypy'])
Table 2-7. Mutable Set Type Methods
Method or Operation
Description
add(item)
Adds an item to a set if it is not already in the set
clear()
Removes all items in a set
difference_update(set2)
Returns the set with all elements contained in set2 removed
discard(element)
Removes designated element from set if present
intersection_update(set2)
Returns the set keeping only those elements that are also in set2
pop()
Return an arbitrary element from the set
remove(element)
Remove element from set if present, if not then KeyError is raised
47
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Table 2-7. Mutable Set Type Methods (continued)
Method or Operation
Description
symmetric_difference_update(set2)
Replace the calling set with a set containing elements from
either the calling set or set2 but not both, and return it
update(set2)
Returns set including all elements from set2
Listing 2-23. More Using Sets
# Create
>>> s1 =
>>> s2 =
>>> s3 =
three sets
Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
Set([5, 10, 15, 20])
Set([2, 4, 6, 8, 10])
# Remove arbitrary element from s2
>>> s2.pop()
20
>>> s2
Set([5, 15, 10])
# Discard the element that equals 3 from s1 (if exists)
>>> s1.discard(3)
>>> s1
Set([6, 5, 7, 8, 2, 9, 10, 1, 4])
# Update s1 to include only those elements contained in both s1 and s2
>>> s1.intersection_update(s2)
>>> s1
Set([5, 10])
>>> s2
Set([5, 15, 10])
# Remove all elements in s2
>>> s2.clear()
>>> s2
Set([])
# Updates set s1 to include all elements in s3
>>> s1.update(s3)
>>> s1
Set([6, 5, 8, 2, 10, 4])
Ranges
The range is a special function that allows one to iterate between a range of numbers or list a specific
range of numbers. It is especially helpful for performing mathematical iterations, but it can also be used
for simple iterations.
The format for using the range function includes an optional starting number, an ending number,
and an optional stepping number. If specified, the starting number tells the range where to begin,
48
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
whereas the ending number specifies where the range should end. The starting index is inclusive
whereas the ending index is not. The optional step number tells the range how many numbers should be
placed between each number contained within the range output. The step number is added to the
previous number and if that number exceeds the end point then the range stops.
Range Format
range([start], stop, [step])
Listing 2-24. Using the Range Function
#Simple range starting with zero, note that the end point is not included in the range
>>>range(0,10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(50, 65)
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64]
>>>range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Include a step of two in the range
>>>range(0,10,2)
[0, 2, 4, 6, 8]
# Including a negative step performs the same functionality...the step is added to the
previously
# number in the range
>>> range(100,0,-10)
[100, 90, 80, 70, 60, 50, 40, 30, 20, 10]
One of the most common uses for this function is in a for loop. The following example displays a
couple ways of using the range function within a for loop context.
Listing 2-25. Using the Range Function Within a For Loop
>>> for i in range(10):
...
print i
...
0
1
2
3
4
5
6
7
8
9
# Multiplication Example
>>> x = 1
>>> for i in range(2, 10, 2):
...
x = x + (i * x)
...
print x
49
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
...
3
15
105
945
As you can see, a range can be used to iterate through just about any number set. . .be it going up or
down, positive or negative in step. Ranges are also a good way to create a list of numbers. In order to do
so, simply pass a range to list() as shown in the following example.
Listing 2-26. Create a List from a Range
>>> my_number_list = list(range(10))
>>> my_number_list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
As you can see, not only are ranges useful for iterative purposes but they are also a good way to
create numeric lists.
Jython-specific Collections
There are a number of Jython-specific collection objects that are available for use. Most of these
collection objects are used to pass data into Java classes and so forth, but they add additional
functionality into the Jython implementation that will assist Python newcomers that are coming from
the Java world. Nonetheless, many of these additional collection objects can be quite useful under
certain situations.
In the Jython 2.2 release, Java collection integration was introduced. This enables a bidirectional
interaction between Jython and Java collection types. For instance, a Java ArrayList can be imported in
Jython and then used as if it were part of the language. Prior to 2.2, Java collection objects could act as a
Jython object, but Jython objects could not act as Java objects. For instance, it is possible to use a Java
ArrayList in Jython and use methods such as add(), remove(), and get(). You will see in the example below
that using the add() method of an ArrayList will add an element to the list and return a boolean to signify
the success or failure of the addition. The remove() method acts similarly, except that it removes an
element rather than adding it.
Listing 2-27. Example of Using Java Oriented Collection in Jython
# Import and use a Java ArrayList
>>> import java.util.ArrayList as ArrayList
>>> arr = ArrayList()
# Add method will add an element to the list and return a boolean to signify successsful
addition
>>> arr.add(1)
True
>>> arr.add(2)
True
>>> print arr
[1, 2]
Ahead of the integration of Java collections, Jython also had implemented the jarray object which
basically allows for the construction of a Java array in Jython. In order to work with a jarray, simply
define a sequence type in Jython and pass it to the jarray object along with the type of object contained
50
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
within the sequence. The jarray is definitely useful for creating Java arrays and then passing them into
java objects, but it is not very useful for working in Jython objects. Moreover, all values within a jarray
must be the same type. If you try to pass a sequence containing multiple types to a jarray then you’ll be
given a TypeError of one kind or another. See Table 2-8 for a listing of character typecodes used with
jarray.
Table 2-8. Character Typecodes for Use With Jarray
Character
Java Equivalent
z
boolean
b
byte
c
char
d
Double
f
Float
h
Short
i
Int
l
Long
Listing 2-28. Jarray Usage
>>> my_seq = (1,2,3,4,5)
>>> from jarray import array
>>> array(my_seq,'i')
array('i', [1, 2, 3, 4, 5])
>>> myStr = "Hello Jython"
>>> array(myStr,'c')
array('c', 'Hello Jython')
Another useful feature of the jarray is that we can create empty arrays if we wish by using the zeros()
method. The zeros() method works in a similar fashion to the array() method which we’ve already
demonstrated. In order to create an array that is empty, simply pass the length of the array along with
the type to the zeros() method. Let’s take a quick look at an example.
51
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Listing 2-29. Create an Empty Boolean Array
>>> arr = zeros(10,'z')
>>> arr
array('z', [False, False, False, False, False, False, False, False, False, False])
Listing 2-30. Create an Empty Integer Array
>>> arr2 = zeros(6, 'i')
>>> arr2
array('i', [0, 0, 0, 0, 0, 0])
In some circumstances when working with Java objects, you will need to call a Java method that
requires a Java array as an argument. Using the jarray object allows for a simple way of creating Java
arrays when needed.
Files
File objects are used to read and write data to a file on disk. The file object is used to obtain a reference
to the file on disk and open it for reading, writing, appending, or a number of different tasks. If we simply
use the open(filename[, mode]) function, we can return a file object and assign it to a variable for
processing. If the file does not yet exist on disk, then it will automatically be created. The mode argument
is used to tell what type of processing we wish to perform on the file. This argument is optional and if
omitted then the file is opened in read-only mode. See Table 2-9.
Table 2-9. Modes of Operations for File Types
Mode
Description
‘r’
read only
‘w’
write (Note: This overwrites anything else in the file, so use with caution)
‘a’
append
‘r+’
read and write
‘rb’
binary file read
‘wb’
binary file write
‘r+b’
binary file read and write
52
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Listing 2-31.
# Open a file and assign it to variable f
>>> f = open('newfile.txt','w')
There are plenty of methods that can be used on file objects for manipulation of the file content. We
can call read([size]) on a file in order to read its content. Size is an optional argument here and it is used
to tell how much content to read from the file. If it is omitted then the entire file content is read. The
readline() method can be used to read a single line from a file. readlines([size]) is used to return a list
containing all of the lines of data that are contained within a file. Again, there is an optional size
parameter that can be used to tell how many bytes from the file to read. If we wish to place content into
the file, the write(string) method does just that. The write() method writes a string to the file.
When writing to a file it is oftentimes important to know exactly what position in the file you are
going to write to. There are a group of methods to help us out with positioning within a file using
integers to represent bytes in the file. The tell() method can be called on a file to give the file object’s
current position. The integer returned is in a number of bytes and is an offset from the beginning of the
file. The seek(offset, from) method can be used to change position in a file. The offset is the number in
bytes of the position you’d like to go, and from represents the place in the file where you’d like to
calculate the offset from. If from equals 0, then the offset will be calculated from the beginning of the file.
Likewise, if it equals 1 then it is calculated from the current file position, and 2 will be from the end of the
file. The default is 0 if from is omitted.
Lastly, it is important to allocate and de-allocate resources efficiently in our programs or we will
incur a memory overhead and leaks. Resources are usually handled a bit differently between CPython
and Jython because garbage collection acts differently. In CPython, it is not as important to worry about
de-allocating resources as they are automatically de-allocated when they go out of scope. The JVM does
note immediately garbage collect, so proper de-allocation of resources is more important. The close()
method should be called on a file when we are through working with it. The proper methodology to use
when working with a file is to open, process, and then close each time. However, there are more efficient
ways of performing such tasks. In Chapter 7 we will discuss the use of context managers to perform the
same functionality in a more efficient manner.
Listing 2-32. File Manipulation in Python
# Create a file, write to it, and then read its content
>>> f = open('newfile.txt','r+')
>>> f.write('This is some new text for our file\n')
>>> f.write('This should be another line in our file\n')
# No lines will be read because we are at the end of the written content
>>> f.read()
''
>>> f.readlines()
[]
>>> f.tell()
75L
# Move our position back to the beginning of the file
>>> f.seek(0)
>>> f.read()
'This is some new text for our file\nThis should be another line in our file\n'
>>> f.seek(0)
>>> f.readlines()
['This is some new text for our file\n', 'This should be another line in our file\n']
53
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
# Closing the file to de-allocate
>>> f.close()
Iterators
The iterator was introduced into Python back in version 2.2. It allows for iteration over Python
containers. All iterable containers have built-in support for the iterator type. For instance, sequence
objects are iterable as they allow for iteration over each element within the sequence. If you try to return
an iterator on an object that does not support iteration, you will most likely receive an AttributeError
which tells you that __iter__ has not been defined as an attribute for that object. It is important to note
that Python method names using double-underscores are special methods. For instance, in Python a
class can be initialized using the __init__() method. . .much like a Java constructor. For more details on
classes and special class methods, please refer to Chapter 7.
Iterators allow for easy access to sequences and other iterable containers. Some containers such as
dictionaries have specialized iteration methods built into them as you have seen in previous sections.
Iterator objects are required to support two main methods that form the iterator protocol. Those
methods are defined below in Table 2-10.
Table 2-10. Iterator Protocol
Method
Description
iterator.__iter__()
Returns the iterator object on a container. Required to allow use with for and in
statements
iterator.next()
Returns the next item from a container.
To return an iterator on a container, just assign container.__iter__() to some variable. That variable
will become the iterator for the object. This affords one the ability to pass iterators around, into
functions and the like. The iterator is then itself like a changing variable that maintains its state. We can
use work with the iterator without affecting the original object. If using the next() call, it will continue to
return the next item within the list until all items have been retrieved. Once this occurs, a StopIteration
exception is issued. The important thing to note here is that we are actually creating a copy of the list
when we return the iterator and assign it to a variable. That variable returns and removes an item from
that copy each time the next() method is called on it. If we continue to call next() on the iterator variable
until the StopIteration error is issued, the variable will no longer contain any items and is empty. For
instance, if we created an iterator from a list then called the next() method on it until it had retrieved all
values then the iterator would be empty and the original list would be left untouched.
Listing 2-33. Create an Iterator from a List and Use It
>>> hockey_roster = ['Josh', 'Leo', 'Frank', 'Jim', 'Vic']
>>> hockey_itr = hockey_roster.__iter__()
>>> hockey_itr = hockey_roster.__iter__()
>>> hockey_itr.next()
'Josh'
>>> for x in hockey_itr:
...
print x
...
54
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Leo
Frank
Jim
Vic
# Try to call next() on iterator after it has already used all of its elements
>>> hockey_itr.next()
Traceback (most recent call last):
File "", line 1, in
StopIteration
Listing 2-34. Iteration Over Sequence and List
# Iterate over a string and a list
>>> str_a = 'Hello'
>>> list_b = ['Hello','World']
>>> for x in str_a:
...
print x
...
H
e
l
l
o
>>> for y in list_b:
...
print y + '!'
...
Hello!
World!
Referencing and Copies
Creating copies and referencing items in the Python language is fairly straightforward. The only thing
you’ll need to keep in mind is that the techniques used to copy mutable and immutable objects differ a
bit.
In order to create a copy of an immutable object, you simply assign it to a different variable. The
new variable is an exact copy of the object. If you attempt to do the same with a mutable object, you will
actually just create a reference to the original object. Therefore, if you perform operations on the “copy”
of the original then the same operation will actually be performed on the original. This occurs because
the new assignment references the same mutable object in memory as the original. It is kind of like
someone calling you by a different name. One person may call you by your birth name and another may
call you by your nickname, but both names will reference you of course.
Listing 2-35. Working with Copies
# Strings are immutable, so when you assign a string to another variable, it creates a real
copy
>>> mystring = "I am a string, and I am an immutable object"
>>> my_copy = mystring
>>> my_copy
'I am a string, and I am an immutable object'
>>> mystring
'I am a string, and I am an immutable object'
55
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
>>> my_copy = "Changing the copy of mystring"
>>> my_copy
'Changing the copy of mystring'
>>> mystring
'I am a string, and I am an immutable object'
# Lists are mutable objects, so assigning a list to a variable
# creates a reference to that list. Changing one of these variables will also
# change the other one – they are just references to the same object.
>>> listA = [1,2,3,4,5,6]
>>> print listA
[1, 2, 3, 4, 5, 6]
>>> listB = listA
>>> print listB
[1, 2, 3, 4, 5, 6]
>>> del listB[2]
# Oops, we’ve altered the original list!
>>> print listA
[1, 2, 4, 5, 6]
# If you want a new list which contains the same things, but isn't just a reference
# to your original list, you need the copy module
>>> import copy
>>> a = [[]]
>>> b = copy.copy(a)
>>> b
[[]]
# b is not the same list as a, just a copy
>>> b is a
False
# But the list b[0] is the same the same list as the list a[0], and changing one will
# also change the other. This is what is known as a shallow copy – a and b are
# different at the top level, but if you go one level down, you have references to
# to the same things – if you go deep enough, it's not a copy,
# it's the same object.
>>> b[0].append('test')
>>> a
[['test']]
>>> b
[['test']]
To effectively create a copy of a mutable object, you have two choices. You can either create what is
known as a shallow copy or a deep copy of the original object. The difference is that a shallow copy of an
object will create a new object and then populate it with references to the items that are contained in the
original object. Hence, if you modify any of those items then each object will be affected since they both
reference the same items.
A deep copy creates a new object and then recursively copies the contents of the original object into
the new copy. Once you perform a deep copy of an object then you can perform operations on any
object contained in the copy without affecting the original. You can use the deepcopy function in the
copy module of the Python standard library to create such a copy. Let’s look at some more examples of
creating copies in order to give you a better idea of how this works.
56
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
Listing 2-36.
# Create an integer variable, copy it, and modify the copy
>>> a = 5
>>> b = a
>>> print b
5
>>> b = a * 5
>>> b
25
>>> a
5
# Create a deep copy of the list and modify it
>>> import copy
>>> listA = [1,2,3,4,5,6]
>>> listB = copy.deepcopy(listA)
>>>
[1,
>>>
>>>
[1,
>>>
[1,
print listB
2, 3, 4, 5, 6]
del listB[2]
print listB
2, 4, 5, 6]
print listA
2, 3, 4, 5, 6]
Garbage Collection
This is one of those major differences between CPython and Jython. In CPython, an object is garbage
collected when it goes out of scope or is no longer needed. This occurs automatically and rarely needs to
be tracked by the developer. Behind the scenes, CPython uses a reference counting technique to
maintain a count on each object which effectively determines if the object is still in use. Unlike CPython,
Jython does not implement a reference counting technique for aging out or garbage collection unused
objects. Instead, Jython makes use of the garbage collection mechanisms that the Java platform
provides. When a Jython object becomes stale or unreachable, the JVM may or may not reclaim it. One
of the main aspects of the JVM that made developers so happy in the early days is that there was no
longer a need to worry about cleaning up after your code. In the C programming language, one must
maintain an awareness of which objects are currently being used so that when they are no longer needed
the program would perform some clean up. Not in the Java world, the gc thread on the JVM takes care of
all garbage collection and cleanup for you.
Even though we haven’t spoken about classes in detail yet, you saw a short example of how them in
Chapter 1. It is a good time to mention that Python provides a mechanism for object cleanup. A finalizer
method can be defined in any class in order to ensure that the garbage collector performs specific tasks.
Any cleanup code that needs to be performed when an object goes out of scope can be placed within this
finalizer method. It is important to note that the finalizer method cannot be counted on as a method
which will always be invoked when an object is stale. This is the case because the finalizer method is
invoked by the Java garbage collection thread, and there is no way to be sure when and if the garbage
collector will be called on an object. Another issue of note with the finalizer is that they incur a
performance penalty. If you’re coding an application that already performs poorly then it may not be a
good idea to throw lots of finalizers into it.
57
www.it-ebooks.info
CHAPTER 2 ■ DATA TYPES AND REFERNCING
The following is an example of a Python finalizer. It is an instance method that must be named
__del__.
Listing 2-37. Python Finalizer Example
class MyClass:
def __del__(self):
pass
# Perform some cleanup here
The downside to using the JVM garbage collection mechanisms is that there is really no guarantee as
to when and if an object will be reclaimed. Therefore, when working with performance intensive objects
it is best to not rely on a finalizer to be called. It is always important to ensure that proper coding
techniques are used in such cases when working with objects like files and databases. Never code the
close() method for a file into a finalizer because it may cause an issue if the finalizer is not invoked. Best
practice is to ensure that all mandatory cleanup activities are performed before a finalizer would be
invoked.
Summary
A lot of material was covered in this chapter. You should be feeling better acquainted with Python after
reading through this material. We began the chapter by covering the basics of assignment an assigning
data to particular objects or data types. You learned that working with each type of data object opens
different doors as the way we work with each type of data object differs. Our journey into data objects
began with numbers and strings, and we discussed the many methods available to the string object. We
learned that strings are part of the sequence family of Python collection objects along with lists and
tuples. We covered how to create and work with lists, and the variety of options available to us when
using lists. You discovered that list comprehensions can help create copies of a given list and manipulate
their elements according to an expression or function. After discussing lists, we went on to discuss
dictionaries, sets and tuples.
After discussing the collection types, we learned that Jython has its own set of collection objects that
differ from those in Python. We can leverage the advantage of having the Java platform at our fingertips
and use Java collection types from within Jython. We finished up by discussing referencing, copies, and
garbage collection. Creating different copies of objects does not always give you what you’d expect, and
that Jython garbage collection differs quite a bit from that of Python.
The next chapter will help you to combine some of the topics you’ve learned about in this chapter as
you will learn how to define expressions and work with control flow.
58
www.it-ebooks.info
CHAPTER 3
■■■
Operators, Expressions, and
Program Flow
The focus of this chapter is an in-depth look at each of the ways that we can evaluate code, and write
meaningful blocks of conditional logic. We’ll cover the details of many operators that can be used in
Python expressions. This chapter will also cover some topics that have already been discussed in more
meaningful detail such as the looping constructs, and some basic program flow.
We’ll begin by discussing details of expressions. If you’ll remember from Chapter 1, an expression is
a piece of code that evaluates to produce a value. We have already seen some expressions in use while
reading through the previous chapters. In this chapter, we’ll focus more on the internals of operators
used to create expressions, and also different types of expressions that we can use. This chapter will go
into further detail on how we can define blocks of code for looping and conditionals.
This chapter will also go into detail on how you write and evaluate mathematical expressions, and
Boolean expressions. And last but not least, we'll discuss how you can use augmented assignment
operations to combine two or more operations into one.
Types of Expressions
An expression in Python is a piece of code that produces a result or value. Most often, we think of
expressions that are used to perform mathematical operations within our code. However, there are a
multitude of expressions used for other purposes as well. In Chapter 2, we covered the details of String
manipulation, sequence and dictionary operations, and touched upon working with sets. All of the
operations performed on these objects are forms of expressions in Python. Other examples of
expressions could be pieces of code that call methods or functions, and also working with lists using
slicing and indexing.
Mathematical Operations
The Python contains all of your basic mathematical operations. This section will briefly touch upon each
operator and how it functions. You will also learn about a few built-in functions which can be used to
assist in your mathematical expressions.
Assuming that this is not the first programming language you are learning, there is no doubt that
you are at least somewhat familiar with performing mathematical operations within your programs.
Python is no different than the rest when it comes to mathematics, as with most programming
languages, performing mathematical computations and working with numeric expressions is
straightforward. Table 3-1 lists the numeric operators.
59
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
Table 3-1. Numeric Operators
Operator
Description
+
Addition
-
Subtraction
*
Multiplication
/
Division
//
Truncating Division
%
Modulo (Remainder of Division)
**
Power Operator
+var
Unary Plus
-var
Unary Minus
Most of the operators in Table 3-1 work exactly as you would expect, so for example:
Listing 3-1. Mathematical Operator
# Performing basic mathematical computations
>>> 10 - 6
4
>>> 9 * 7
63
However, division, truncating division, modulo, power, and the unary operators could use some
explanation. Truncating division will automatically truncate a division result into an integer by rounding
down, and modulo will return the remainder of a truncated division operation. The power operator does
just what you’d expect as it returns the result of the number to the left of the operator multiplied by itself
n times, where n represents the number to the right of the operator.
Listing 3-2. Truncating Division and Powers
>>> 36 // 5
7
# Modulo returns the remainder
>>> 36 % 5
1
# Using powers, in this case 5 to the power of 2
>>> 5**2
25
60
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
# 100 to the power of 2
>>> 100**2
10000
Division itself is an interesting subject as its current implementation is somewhat controversial in
some situations. The problem 10/5 = 2 definitely holds true. However, in its current implementation,
division rounds numbers in such a way that sometimes yields unexpected results. There is a new means
of division available in Jython 2.5 by importing from __future__. In a standard division for 2.5 and
previous releases, the quotient returned is the floor (nearest integer after rounding down) of the quotient
when arguments are ints or longs. However, a reasonable approximation of the division is returned if the
arguments are floats or complex. Often times this solution is not what was expected as the quotient
should be the reasonable approximation or “true division” in any case. When we import division from
the __future__ module then we alter the return value of division by causing true division when using the
/ operator, and floor division only when using the , // operator. In an effort to not break backward
compatibility, the developers have placed the repaired division implementation in a module known as
__future__. The __future__ module actually contains code that is meant to be included as a part of the
standard language in some future revision. In order to use the new repaired version of division, it is
important that you always import from __future__ prior to working with division. Take a look at the
following piece of code.
Listing 3-3. Division Rounding Issues
# Works as expected
>>> 14/2
7
>>> 10/5
2
>>> 27/3
9
# Now divide some numbers that should result in decimals
# Here we would expect 1.5
>>> 3/2
1
# The following should give us 1.4
>>> 7/5
1
# In the following case, we'd expect 2.3333
>>> 14/6
2
As you can see, when we’d expect to see a decimal value we are actually receiving an integer value.
The developers of this original division implementation have acknowledged this issue and repaired it
using the new __future__ implementation.
Listing 3-4. Working With __future__ Division
# We first import division from __future__
from __future__ import division
# We then work with division as usual and see the expected results
>>> 14/2
7.0
>>> 10/5
61
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
2.0
>>> 27/3
9.0
>>> 3/2
1.5
>>> 7/5
1.4
>>> 14/6
2.3333333333333335
It is important to note that the Jython implementation differs somewhat from CPython in that Java
provides extra rounding in some cases. The differences are in display of the rounding only as both
Jython and CPython use the same IEEE float for storage. Let’s take a look at one such case.
Listing 3-5. Subtle Differences Between Jython and CPython Division
# CPython 2.5 Rounding
>>> 5.1/1
5.0999999999999996
# Jython 2.5
>>> 5.1/1
5.1
Unary operators can be used to evaluate positive or negative numbers. The unary plus operator
multiplies a number by positive 1 (which generally doesn’t change it at all), and a unary minus operator
multiplies a number by negative 1.
Listing 3-6. Unary Operators
# Unary minus
>>> -10 + 5
-5
>>> +5 - 5
0
>>> -(1 + 2)
-3
As stated at the beginning of the section, there are a number of built-in mathematical functions that
are at your disposal. Table 3-2 lists the built-in mathematical functions.
62
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
Table 3-2. Mathematical Built-in Functions
Function
Description
abs(var)
Absolute value
pow(x, y)
Can be used in place of ** operator
pow(x,y,modulo)
Ternary power-modulo (x **y) % modulo
round(var[, n])
Returns a value rounded to the nearest 10-n or (10**-n), where n defaults to 0)
divmod(x, y)
Returns a tuple of the quotient and the remainder of division
Listing 3-7. Mathematical Built-ins
# The following code provides some examples for using mathematical built-ins
# Absolute value of 9
>>> abs(9)
9
# Absolute value of -9
>>> abs(-9)
9
# Divide 8 by 4 and return quotient, remainder tuple
>>> divmod(8,4)
(2, 0)
# Do the same, but this time returning a remainder (modulo)
>>> divmod(8,3)
(2, 2)
# Obtain 8 to the power of 2
>>> pow(8,2)
64
# Obtain 8 to the power of 2 modulo 3
>>> pow(8,2,3)
1
# Perform rounding
>>> round(5.67,1)
5.7
>>> round(5.67)
6.00
((8 **2) % 3)
Comparison Operators
Comparison operators can be used for comparison of two or more expressions or variables. As with the
mathematical operators described above, these operators have no significant difference to that of Java.
See Table 3-3.
63
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
Table 3-3. Comparison Operators
Operator
Description
>
Greater than
<
Less than
>=
Greater than or equal
<=
Less than or equal
!=
Not equal
==
Equal
Listing 3-8. Examples of Comparison Operators
# Simple comparisons
>>> 8 > 10
False
>>> 256 < 725
True
>>> 10 == 10
True
# Use comparisons in an expression
>>> x = 2*8
>>> y = 2
>>> while x != y:
...
print 'Doing some work...'
...
y = y + 2
...
Doing some work...
Doing some work...
Doing some work...
Doing some work...
Doing some work...
Doing some work...
Doing some work...
# Combining comparisons
>>> 3<2<3
False
>>> 3<4<8
True
64
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
Bitwise Operators
Bitwise operators in Python are a set of operators that are used to work on numbers in a two’s
complement binary fashion. That is, when working with bitwise operators numbers are treated as a
string of bits consisting of 0s and 1s. If you are unfamiliar with the concept of two's complement, a good
place to start would be at the Wikipedia page discussing the topic:
(http://en.wikipedia.org/wiki/Two's_complement). It is important to know that bitwise operators can
only be applied to integers and long integers. Let’s take a look at the different bitwise operators that are
available to us (Table 3-4), and then we’ll go through a few examples.
Table 3-4. Bitwise Operators
Operator
Description
&
Bitwise and operator copies a bit to the result if a bit appears in both operands
|
Bitwise or operator copies a bit to the result if it exists in either of the operands
^
Bitwise xor operator copies a bit to the result if it exists in only one operand
~
Bitwise negation operator flips the bits, and returns the exact opposite of each bit
Suppose we have a couple of numbers in binary format and we would like to work with them using
the bitwise operators. Let’s work with the numbers 14 and 27. The binary (two's complement)
representation of the number 14 is 00001110, and for 27 it is 00011011. The bitwise operators look at
each 1 and 0 in the binary format of the number and perform their respective operations, and then
return a result. Python does not return the bits, but rather the integer value of the resulting bits. In the
following examples, we take the numbers 14 and 27 and work with them using the bitwise operators.
Listing 3-9. Bitwise Operator Examples
>>>
10
>>>
31
>>>
21
>>>
-15
>>>
-28
14 & 27
14 | 27
14 ^ 27
~14
~27
To summarize the examples above, let’s work through the operations using the binary
representations for each of the numbers.
14 & 27 = 00001110 and 00011011 = 00001010 (The integer 10)
14 | 27 = 00001110 or 000110011 = 00011111 (The integer 31)
14 ^ 27 = 00001110 xor 000110011 = 00010101 (The integer 21)
~14 = 00001110 = 11110001 (The integer -15)
The shift operators (see Table 3-5) are similar in that they work with the binary bit representation of
a number. The left shift operator moves the left operand’s value to the left by the number of bits
65
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
specified by the right operand. The right shift operator does the exact opposite as it shifts the left
operand's value to the right by the number of bits specified by the right operand. Essentially this
translates to the left shift operator multiplying the operand on the left by the number two as many times
as specified by the right operand. The opposite holds true for the right shift operator that divides the
operand on the left by the number two as many times as specified by the right operand.
Table 3-5. Shift Operators
x<>n
Shift right (The equivalent of dividing the number x by 2, n times)
More specifically, the left shift operator (<<) will multiply a number by two n times, n being the
number that is to the right of the shift operator. The right shift operator will divide a number by two n
times, n being the number to the right of the shift operator. The __future__division import does not
make a difference in the outcome of such operations.
Listing 3-10. Shift Operator Examples
# Shift left, in this case 3*2
>>> 3<<1
6
# Equivalent of 3*2*2
>>> 3<<2
12
# Equivalent of 3*2*2*2*2*2
>>> 3<<5
96
# Shift right
# Equivalent of
>>> 3>>1
1
# Equivalent of
>>> 9>>1
4
# Equivalent of
>>> 10>>1
5
# Equivalent of
>>> 10>>2
2
3/2
9/2
10/2
10/2/2
While bitwise operators are not the most commonly used operators, they are good to have on hand.
They are especially important if you are working in mathematical situations.
Augmented Assignment
Augmented assignment operators (see Table 3-6) combine an operation with an assignment. They can
be used to do things like assign a variable to the value it previously held, modified in some way. While
66
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
augmented assignment can assist in coding concisely, some say that too many such operators can make
code more difficult to read.
Listing 3-11. Augmented Assignment Code Examples
>>> x = 5
>>> x
5
# Add one to the value of x and then assign that value to x
>>> x+=1
>>> x
6
# Multiply the value of x by 5 and then assign that value to x
>>> x*=5
>>> x
30
Table 3-6. Augmented Assignment Operators
Operator Equivalent
a += b
a=a+b
a -= b
a=a–b
a *= b
a=a*b
a /= b
a=a/b
a %= b
a=a%b
a //= b
a = a // b
a **= b
a = a** b
a &= b
a=a&b
a |= b
a=a|b
a ^= b
a=a^b
a >>= b
a = a >> b
a <<= b
a = a << b
67
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
Boolean Expressions
Evaluating two or more values or expressions also uses a similar syntax to that of other languages, and
the logic is quite the same. Note that in Python, True and False are very similar to constants in the Java
language. True actually represents the number 1, and False represents the number 0. One could just as
easily code using 0 and 1 to represent the Boolean values, but for readability and maintenance the True
and False “constants” are preferred. Java developers, make sure that you capitalize the first letter of these
two words as you will receive an ugly NameError if you do not.
Boolean properties are not limited to working with int and bool values, but they also work with
other values and objects. For instance, simply passing any non-empty object into a Boolean expression
will evaluate to True in a Boolean context. This is a good way to determine whether a string contains
anything. See Table 3-7.
Listing 3-12. Testing a String
>>> mystr = ''
>>> if mystr:
...
'Now I contain the following: %s' % (mystr)
... else:
...
'I do not contain anything'
...
'I do not contain anything'
>>> mystr = 'Now I have a value'
>>> if mystr:
...
'Now I contain the following: %s' % (mystr)
... else:
...
'I do not contain anything'
...
'Now I contain the following: Now I have a value'
Table 3-7. Boolean Conditionals
Conditional
Logic
and
In an x and y evaluation, if x evaluates to false then its value is returned, otherwise y is
evaluated and the resulting value is returned
or
In an x or y evaluation, if x evaluates to true then its value is returned, otherwise y is
evaluated and the resulting value is returned
not
In a not x evaluation, if not x, we mean the opposite of x
As with all programming languages, there is an order of operations for deciding what operators are
evaluated first. For instance, if we have an expression a + b *c, then which operation would take place
first? The order of operations for Python is shown in Table 3-8 with those operators that receive the
highest precedence shown first, and those with the lowest shown last. Repeats of the same operator are
grouped from left to the right with the exception of the power (**) operator.
68
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
Table 3-8. Python Order of Operations
Operator Precedence from Highest to Lowest
Name
+var, -var, ~var
Unary Operations
**
Power Operations
*, /, //, %
Multiplication, Division, Floor Division, Modulo
+, -
Addition, Subtraction
<<, >>
Left and Right Shift
&
Bitwise And
^
Bitwise Exclusive Or
|
Bitwise Or
<, >, <=. >= , <>
Comparison Operators
==, != , is, is not, in, not in
Equality and Membership
and, or, not
Boolean Conditionals
An important note is that when working with Boolean conditionals, 'and' and 'or' group from the left
to the right. Let’s take a look at a few examples.
Listing 3-13. Order of Operations Examples
# Define a few variables
>>> x = 10
>>> y = 12
>>> z = 14
# (y*z) is evaluated first, then x is added
>>> x + y * z
178
# (x * y) is evaluated first, then z is subtracted from the result
>>> x * y - z
106
# When chaining comparisons, a logical 'and' is implied.
# case, x < y and y <= z and z > x
>>> x < y <= z > x
True
In this
69
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
# (2 * 0) is evaluated first and since it is False or zero, it is returned
>>> 2 * 0 and 5 + 1
0
# (2 * 1) is evaluated first, and since it is True or not zero, the (5 + 1) is evaluated and
# returned
>>> 2 * 1 and 5 + 1
6
# x is returned if it is True, otherwise y is returned if it is False.
# of those two conditions occur, then z is returned.
>>> x or (y and z)
10
If neither
# In this example, the (7 – 2) is evaluated and returned because of the 'and' 'or'
# logic
>>> 2 * 0 or ((6 + 8) and (7 - 2))
5
# In this case, the power operation is evaluated first, and then the addition
>>> 2 ** 2 + 8
12
Conversions
There are a number of conversion functions built into the language in order to help conversion of one
data type to another (see Table 3-9). While every data type in Jython is actually a class object, these
conversion functions will really convert one class type into another. For the most part, the built-in
conversion functions are easy to remember because they are primarily named after the type to which
you are trying to convert.
Table 3-9. Conversion Functions
Function
Description
chr(value)
Converts integer to a character
complex(real
[,imag])
Produces a complex number
dict(sequence)
Produces a dictionary from a given sequence of (key, value) tuples
eval(string)
Evaluates a string to return an object…useful for mathematical computations. Note:
This function should be used with extreme caution as it can pose a security hazard if
not used properly.
float(value)
Converts number to float
70
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
Table 3-9. Conversion Functions (continued)
frozenset(set)
Converts a set into a frozen set
hex(value)
Converts an integer into a string representing that number in hex
int(value [, base])
Converts to an integer using a base if a string is given
list(sequence)
Converts a given sequence into a list
long(value [,
base])
Converts to a long using a base if a string is given
oct(value)
Converts an integer to a string representing that number as an octal
ord(value)
Converts a character into its integer value
repr(value)
Converts object into an expression string. Same as enclosing expression in reverse
quotes ( `x + y`). Returns a string containing a printable and evaluable
representation of the object
set(sequence)
Converts a sequence into a set
str(value)
Converts an object into a string Returns a string containing a printable
representation of the value, but not an evaluable string
tuple(sequence)
Converts a given sequence to a tuple
unichr(value)
Converts integer to a Unicode character
Listing 3-14. Conversion Function Examples
# Return the character representation of the integers
>>> chr(4)
'\x04'
>>> chr(10)
'\n'
# Convert intger to float
>>> float(8)
8.0
# Convert character to its integer value
>>> ord('A')
65
>>> ord('C')
67
71
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
>>> ord('z')
122
# Use repr() with any object
>>> repr(3.14)
'3.14'
>>> x = 40 * 5
>>> y = 2**8
>>> repr((x, y, ('one','two','three')))
"(200, 256, ('one', 'two', 'three'))"
The following is an example of using the eval() functionality as it is perhaps the one conversion
function for which an example helps to understand. Again, please note that using the eval() function can
be dangerous and impose a security threat if used incorrectly. If using the eval() function to accept text
from a user, standard security precautions should be set into place to ensure that the string being
evaluated is not going to compromise security.
Listing 3-15. Example of eval()
# Suppose keyboard input contains an expression in string format (x * y)
>>> x = 5
>>> y = 12
>>> keyboardInput = 'x * y'
# We should provide some security checks on the keyboard input here to
# ensure that the string is safe for evaluation. Such a task is out of scope
# for this chapter, but it is good to note that comparisons on the keyboard
# input to check for possibly dangerous code should be performed prior to
# evaluation.
>>> eval(keyboardInput)
60
Using Expressions to Control Program Flow
As you’ve learned in previous references in this book, the statements that make up programs in Python
are structured with attention to spacing, order, and technique. Each section of code must be consistently
spaced as to set each control structure apart from others. One of the great advantages to Python’s syntax
is that the consistent spacing allows for delimiters such as the curly braces {} to go away. For instance, in
Java one must use curly braces around a for loop to signify a start and an end point. Simply spacing a for
loop in Python correctly takes place of the braces. Convention and good practice adhere to using four
spaces of indentation per statement throughout the entire program. For more information on
convention, please see PEP 8, Style Guide for Python Code (www.python.org/dev/peps/pep-0008/).
Follow this convention along with some control flow and you’re sure to develop some easily
maintainable software.
if-elif-else Statement
The standard Python if-elif-else conditional statement is used in order to evaluate expressions and
branch program logic based upon the outcome. An if-elif-else statement can consist of any expressions
we’ve discussed previously. The objective is to write and compare expressions in order to evaluate to a
True or False outcome. As shown in Chapter 1, the logic for an if-elif-else statement follows one path if an
expression evaluates to True, or a different path if it evaluates to False.
72
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
You can chain as many if-else expressions together as needed. The combining if-else keyword is elif,
which is used for every expression in between the first and the last expressions within a conditional
statement.
The elif portion of the statement helps to ensure better readability of program logic. Too many if
statements nested within each other can lead to programs that are difficult to maintain. The initial if
expression is evaluated, and if it evaluates to False, the next elif expression is evaluated, and if it
evaluates to False then the process continues. If any of the if or elif expressions evaluate to True then the
statements within that portion of the if statement are processed. Eventually if all of the expressions
evaluate to False then the final else expression is evaluated.
These next examples show a few ways for making use of a standard if-elif-else statement. Note that
any expression can be evaluated in an if-elif-else construct. These are only some simplistic examples, but
the logic inside the expressions could become as complex as needed.
Listing 3-16. Standard if-elif-else
# terminal symbols are left out of this example so that you can see the precise indentation
pi =3.14
x = 2.7 * 1.45
if x == pi:
print 'The number is pi'
elif x > pi:
print 'The number is greater than pi'
else:
print 'The number is less than pi'
Empty lists or strings will evaluate to False as well, making it easy to use them for comparison
purposes in an if-elif-else statement.
Listing 3-17. Evaluate Empty List
# Use an if-statement to determine whether a list is empty
# Suppose mylist is going to be a list of names
>>> mylist = []
>>> if mylist:
...
for person in mylist:
...
print person
... else:
...
print 'The list is empty'
...
The list is empty
while Loop
Another construct that we touched upon in Chapter 1 was the loop. Every programming language
provides looping implementations, and Python is no different. To recap, the Python language provides
two main types of loops known as the while and the for loop.
The while loop logic follows the same semantics as the while loop in Java. The while loop evaluates a
given expression and continues to loop through its statements until the results of the expression no
longer hold true and evaluate to False. Most while loops contain a comparison expression such as x <= y
or the like, in this case the expression would evaluate to False when x becomes greater than y. The loop
will continue processing until the expression evaluates to False. At this time the looping ends and that
73
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
would be it for the Java implementation. Python on the other hand allows an else clause which is
executed when the loop is completed.
Listing 3-18. Python while Statement
>>> x = 0
>>> y = 10
>>> while x <= y:
...
print 'The current value of x is: %d' % (x)
...
x += 1
... else:
...
print 'Processing Complete...'
...
The current value of x is: 0
The current value of x is: 1
The current value of x is: 2
The current value of x is: 3
The current value of x is: 4
The current value of x is: 5
The current value of x is: 6
The current value of x is: 7
The current value of x is: 8
The current value of x is: 9
The current value of x is: 10
Processing Complete...
This else clause can come in handy while performing intensive processing so that we can inform the
user of the completion of such tasks. It can also be handy when debugging code, or when some sort of
cleanup is required after the loop completes
Listing 3-19. Resetting Counter Using with-else
>>>
>>>
>>>
>>>
...
...
...
...
...
...
210
total = 0
x = 0
y = 20
while x <= y:
total += x
x += 1
else:
print total
total = 0
continue Statement
The continue statement is to be used when you are within a looping construct, and you have the
requirement to tell Python to continue processing past the rest of the statements in the current loop.
Once the Python interpreter sees a continue statement, it ends the current iteration of the loop and goes
on to continue processing the next iteration. The continue statement can be used with any for or while
loop.
74
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
Listing 3-20. Continue Statement
# Iterate over range and print out only the positive numbers
>>> x = 0
>>> while x < 10:
...
x += 1
...
if x % 2 != 0:
...
...
continue
print x
...
2
4
6
8
10
In this example, whenever x is odd, the 'continue' causes execution to move on to the next iteration
of the loop. When x is even, it is printed out.
break Statement
Much like the continue statement, the break statement can be used inside of a loop. We use the break
statement in order to stop the loop completely so that a program can move on to its next task. This
differs from continue because the continue statement only stops the current iteration of the loop and
moves onto the next iteration. Let’s check it out:
Listing 3-21. Break Statement
>>> x = 10
>>> while True:
...
if x == 0:
...
print 'x is now equal to zero!'
...
break
...
if x % 2 == 0:
...
print x
...
x -= 1
...
10
8
6
4
75
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
2
x is now equal to zero!
In the previous example, the loop termination condition is always True, so execution only leaves the
loop when a break is encountered. If we are working with a break statement that resides within a loop
that is contained in another loop (nested loop construct), then only the inner loop will be terminated.
for Loop
The for loop can be used on any iterable object. It will simply iterate through the object and perform
some processing during each pass. Both the break and continue statements can also be used within the
for loop. The for statement in Python also differs from the same statement in Java because in Python we
also have the else clause with this construct. Once again, the else clause is executed when the for loop
processes to completion without any break intervention or raised exceptions. Also, if you are familiar
with pre-Java 5 for loops then you will love the Python syntax. In Java 5, the syntax of the for statement
was adjusted a bit to make it more in line with syntactically easy languages such as Python.
Listing 3-22. Comparing Java and Python for-loop
Example of Java for-loop (pre Java 5)
for(x = 0; x <= myList.size(); x++){
// processing statements iterating through myList
System.out.println("The current index is: " + x);
}
Listing 3-23. Example of Python for-loop
my_list = [1,2,3,4,5]
>>> for value in my_list:
# processing statements using value as the current item in my_list
...
print 'The current value is %s' % (value)
...
The current value is 1
The current value is 2
The current value is 3
The current value is 4
The current value is 5
As you can see, the Python syntax is a little easier to understand, but it doesn’t really save too many
keystrokes at this point. We still have to manage the index (x in this case) by ourselves by incrementing it
with each iteration of the loop. However, Python does provide a built-in function that can save us some
keystrokes and provides a similar functionality to that of Java with the automatically incrementing index
on the for loop. The enumerate(sequence) function does just that. It will provide an index for our use and
automatically manage it for us.
Listing 3-24. Enumerate() Functionality
>>> myList = ['jython','java','python','jruby','groovy']
>>> for index, value in enumerate(myList):
76
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
...
print index, value
...
0 jython
1 java
2 python
3 jruby
4 groovy
If we do not require the use of an index, it can be removed and the syntax can be cleaned up a bit.
>>> myList = ['jython', 'java', 'python', 'jruby', 'groovy']
>>> for item in myList:
...
print item
...
jython
java
python
jruby
groovy
Now we have covered the program flow for conditionals and looping constructs in the Python
language. However, good programming practice will tell you to keep it as simple as possible or the logic
will become too hard to follow. In practicing proper coding techniques, it is also good to know that lists,
dictionaries, and other containers can be iterated over just like other objects. Iteration over containers
using the for loop is a very useful strategy. Here is an example of iterating over a dictionary object.
Listing 3-25. Iteration Over Containers
# Define a dictionary and then iterate over it to print each value
>>> my_dict = {'Jython':'Java', 'CPython':'C', 'IronPython':'.NET', 'PyPy':'Python'}
>>> for key in my_dict:
...
print key
...
Jython
IronPython
CPython
PyPy
It is useful to know that we can also obtain the values of a dictionary object via each iteration by
calling my_dict.values().
Example Code
Let’s take a look at an example program that uses some of the program flow which was discussed in this
chapter. The example program simply makes use of an external text file to manage a list of players on a
sports team. You will see how to follow proper program structure and use spacing effectively in this
example. You will also see file utilization in action, along with utilization of the raw_input() function.
Listing 3-26. # import os module
import os
77
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
# Create empty dictionary
player_dict = {}
# Create an empty string
enter_player = ''
# Enter a loop to enter inforation from keyboard
while enter_player.upper() != 'X':
print 'Sports Team Administration App'
# If the file exists, then allow us to manage it, otherwise force creation.
if os.path.isfile('players.txt'):
enter_player = raw_input("Would you like to create a team or manage an existing
team?\n (Enter 'C' for create, 'M' for manage, 'X' to exit) ")
else:
# Force creation of file if it does not yet exist.
enter_player = 'C'
# Check to determine which action to take.
if enter_player.upper() == 'C':
C = create, M = manage, X = Exit and Save
# Enter a player for the team
print 'Enter a list of players on our team along with their position'
enter_cont = 'Y'
# While continuing to enter new player's, perform the following
while enter_cont.upper() == 'Y':
# Capture keyboard entry into name variable
name = raw_input('Enter players first name: ')
# Capture keyboard entry into position variable
position = raw_input('Enter players position: ')
# Assign position to a dictionary key of the player name
player_dict[name] = position
enter_cont = raw_input("Enter another player? (Press 'N' to exit or 'Y' to
continue)")
else:
enter_player = 'X'
# Manage player.txt entries
elif enter_player.upper() == 'M':
# Read values from the external file into a dictionary object
print
print 'Manage the Team'
# Open file and assign to playerfile
playerfile = open('players.txt','r')
# Use the for-loop to iterate over the entries in the file
for player in playerfile:
# Split entries into key/value pairs and add to list
playerList = player.split(':')
# Build dictionary using list values from file
player_dict[playerList[0]] = playerList[1]
# Close the file
playerfile.close()
78
www.it-ebooks.info
CHAPTER 3 ■ OPERATORS, EXPRESSIONS, AND PROGRAM FLOW
print 'Team Listing'
print '++++++++++++'
# Iterate over dictionary values and print key/value pairs
for i, player in enumerate(player_dict):
print 'Player %s Name: %s -- Position: %s' %(i, player, player_dict[player])
else:
# Save the external file and close resources
if player_dict:
print 'Saving Team Data...'
# Open the file
playerfile = open('players.txt','w')
# Write each dictionary element to the file
for player in player_dict:
playerfile.write('%s:%s\n' % (player.strip(),player_dict[player].strip()))
# Close file
playerfile.close()
This example is packed full of concepts that have been discussed throughout the first three chapters
of the book. As stated previously, the concept is to create and manage a list of sport players and their
relative positions. The example starts by entering a while() loop that runs the program until the user
enters the exit command. Next, the program checks to see if the 'players.txt' file exists. If it does, then the
program prompts the user to enter a code to determine the next action to be taken. However, if the file
does not exist then the user is forced to create at least one player/position pair in the file.
Continuing on, the program allows the user to enter as many player/position pairs as needed, or exit
the program at any time. If the user chooses to manage the player/position list, the program simply
opens the 'players.txt' file, uses a for() loop to iterate over each entry within the file. A dictionary is
populated with the current player in each iteration of the loop. Once the loop has completed, the file is
closed and the dictionary is iterated and printed. Exiting the program forces the else() clause to be
invoked, which iterates over each player in the dictionary and writes them to the file.
Unfortunately, this program is quite simplistic and some features could not be implemented
without knowledge of functions (Chapter 4) or classes (Chapter 6). A good practice would be to revisit
this program once those topics have been covered and simplify as well as add additional functionality.
Summary
All programs are constructed out of statements and expressions. In this chapter we covered details of
creating expressions and using them. Expressions can be composed of any number of mathematical
operators and comparisons. In this chapter we discussed the basics of using mathematical operators in
our programs. The __future__ division topic introduced us to using features from the __future__. We
then delved into comparisons and comparison operators.
We ended this short chapter by discussing proper program flow and properly learned about the if
statement as well as how to construct different types of loops in Python. In the next chapter you will
learn how to write functions, and the use of many built-in functions will be discussed.
79
www.it-ebooks.info
www.it-ebooks.info
CHAPTER 4
■■■
Defining Functions and
Using Built-ins
Functions are the fundamental unit of work in Python. A function in Python performs a task and returns
a result. In this chapter, we will start with the basics of functions. Then we look at using the built-in
functions. These are the core functions that are always available, meaning they don’t require an explicit
import into your namespace. Next we will look at some alternative ways of defining functions, such as
lambdas and classes. We will also look at more advanced types of functions, namely closures and
generator functions.
As you will see, functions are very easy to define and use. Python encourages an incremental style of
development that you can leverage when writing functions. So how does this work out in practice? Often
when writing a function it may make sense to start with a sequence of statements and just try it out in a
console. Or maybe just write a short script in an editor. The idea is to just to prove a path and answer
such questions as, “Does this API work in the way I expect?” Because top-level code in a console or script
works just like it does in a function, it’s easy to later isolate this code in a function body and then
package it as a function, maybe in a library, or as a method as part of a class. The ease of doing this style
of development is one aspect that makes Python such a joy use. And of course in the Jython
implementation, it’s easy to use this technique within the context of any Java library.
An important thing to keep in mind is that functions are first-class objects in Python. They can be
passed around just like any other variable, resulting in some very powerful solutions. We’ll see some
examples of using functions in such a way later in this chapter.
Function Syntax and Basics
Functions are usually defined by using the ‘def’ keyword, the name of the function, its parameters (if
any), and the body of code. We will start by looking at this example function:
Listing 4-1.
def times2(n):
return n * 2
In this example, the function name is times2 and it accepts a parameter n. The body of the function
is only one line, but the work being done is the multiplication of the parameter by the number 2. Instead
of storing the result in a variable, this function simply returns it to the calling code. An example of using
this function would be as follows.
81
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
Listing 4-2.
>>> times2(8)
16
>>> x = times2(5)
>>> x
10
Normal usage can treat function definitions as being very simple. But there’s subtle power in every
piece of the function definition, due to the fact that Python is a dynamic language. We’ll look at these
pieces from both a simple (the more typical case) and a more advanced perspective. We will also look at
some alternative ways of creating functions in a later section.
The def Keyword
Using ‘def’ for define seems simple enough, and this keyword certainly can be used to declare a function
just like you would in a static language. You should write most code that way in fact.
However, a function definition can occur at any level in your code and be introduced at any time.
Unlike the case in a language like C or Java, function definitions are not declarations. Instead they are
executable statements. You can nest functions, and we’ll describe that more when we talk about nested
scopes. And you can do things like conditionally define them.
This means it’s perfectly valid to write code like the following:
Listing 4-3.
if variant:
def f():
print "One way"
else:
def f():
print "or another"
Please note, regardless of when and where the definition occurs, including its variants as above, the
function definition will be compiled into a function object at the same time as the rest of the module or
script that the function is defined in.
Naming the Function
We will describe this more in a later section, but the dir built-in function will tell us about the names
defined in a given namespace, defaulting to the module, script, or console environment we are working
in. With this new times2 function defined above, we now see the following (at least) in the console
namespace:
Listing 4-4.
>>> dir()
['__doc__', '__name__', 'times2']
We can also just look at what is bound to that name:
82
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
Listing 4-5.
>>> times2
(This object is further introspectable. Try dir(times2) and go from there.) We can reference the
function by supplying the function name such as we did in the example above. However, in order to call
the function and make it perform some work, we need to supply the () to the end of the name.
We can also redefine a function at any time:
Listing 4-6.
>>>
...
>>>
...
>>>
Hi,
def f(): print "Hello, world"
def f(): print "Hi, world"
f()
world
This is true not just of running it from the console, but any module or script. The original version of
the function object will persist until it’s no longer referenced, at which point it will be ultimately be
garbage collected. In this case, the only reference was the name f, so it became available for GC
immediately upon rebind.
What’s important here is that we simply rebound the name. First it pointed to one function object,
then another. We can see that in action by simply setting another name (equivalently, a variable) to
times2.
Listing 4-7.
>>> t2 = times2
>>> t2(5)
10
This makes passing a function as a parameter very easy, for a callback for example. A callback is a
function that can be invoked by a function to perform a task and then turn around and invoke the calling
function, thus the callback. Let’s take a look at function parameters in more detail.
FUNCTION METAPROGRAMMING
A given name can only be associated with one function at a time, so can’t overload a function with multiple
definitions. If you were to define two or more functions with the same name, the last one defined is used,
as we saw.
However, it is possible to overload a function, or otherwise genericize it. You simply need to create a
dispatcher function that then dispatches to your set of corresponding functions. Another way to genericize
a function is to make use of the simplegeneric module which lets you define simple single-dispatch
generic functions. For more information, please see the simplegeneric package in the Python Package
Index.
83
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
Function Parameters and Calling Functions
When defining a function, you specify the parameters it takes. Typically you will see something like the
following. The syntax is familiar:
def tip_calc(amt, pct)
As mentioned previously, calling functions is also done by placing parentheses after the function
name. For example, for the function x with parameters a,b,c that would be x(a,b,c). Unlike some other
dynamic languages like Ruby and Perl, the use of parentheses is required syntax (due the function name
being just like any other name).
Objects are strongly typed, as we have seen. But function parameters, like names in general in
Python, are not typed. This means that any parameter can refer to any type of object.
We see this play out in the times2 function. The * operator not only means multiply for numbers, it
also means repeat for sequences (like strings and lists). So you can use the times2 function as follows:
Listing 4-8.
>>> times2(4)
8
>>> times2('abc')
'abcabc'
>>> times2([1,2,3])
[1, 2, 3, 1, 2, 3]
All parameters in Python are passed by reference. This is identical to how Java does it with object
parameters. However, while Java does support passing unboxed primitive types by value, there are no
such entities in Python. Everything is an object in Python. It is important to remember that immutable
objects cannot be changed, and therefore, if we pass a string to a function and alter it, a copy of the
string is made and the changes are applied to the copy.
Listing 4-9.
# The following function changes the text of a string by making a copy
# of the string and then altering it. The original string is left
# untouched as it is immutable.
>>> def changestr(mystr):
...
mystr = mystr + '_changed'
...
print 'The string inside the function: ', mystr
...
return
>>> mystr = 'hello'
>>> changestr(mystr)
The string inside the function: hello_changed
>>> mystr
'hello'
Functions are objects too, and they can be passed as parameters:
Listing 4-10.
# Define a function that takes two values and a mathematical function
>>> def perform_calc(value1, value2, func):
...
return func(value1, value2)
84
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
...
# Define a mathematical function to pass
>>> def mult_values(value1, value2):
...
return value1 * value2
...
>>> perform_calc(2, 4, mult_values)
8
# Define another mathematical function to pass
>>> def add_values(value1, value2):
...
return value1 + value2
...
>>> perform_calc(2, 4, add_values)
6
>>>
If you have more than two or so arguments, it often makes more sense to call a function by named
values, rather than by the positional parameters. This tends to create more robust code. So if you have a
function draw_point(x,y), you might want to call it as draw_point(x=10,y=20).
Defaults further simplify calling a function. You use the form of param=default_value when defining
the function. For instance, you might take our times2 function and generalize it.
Listing 4-11.
def times_by(n, by=2):
return n * by
This function is equivalent to times2 when called with just one argument—it uses the default value
for the second argument by.
There’s one point to remember that often trips up developers. The default value is initialized exactly
once, when the function is defined. That’s certainly fine for immutable values like numbers, strings,
tuples, frozensets, and similar objects. But you need to ensure that if the default value is mutable, that
it’s being used correctly. So a dictionary for a shared cache makes sense. But this mechanism won’t work
for a list where we expect it is initialized to an empty list upon invocation. If you’re doing that, you need
to write that explicitly in your code. As a best practice, use None as the default value rather than a
mutable object, and check at the start of the body of your function for the case value = None and set the
variable to your mutable object there.
Lastly, a function can take an unspecified number of ordered arguments, through *args, and
keyword args, through **kwargs. These parameter names (args and kwargs) are conventional, so you can
use whatever name makes sense for your function. The markers * and ** are used to determine that this
functionality should be used. The single * argument allows for passing a sequence of values, and a
double ** argument allows for passing a dictionary of names and values. If either of these types of
arguments is specified, they must follow any single arguments in the function declaration. Furthermore,
the double ** must follow the single *.
Definition of a function that takes a sequence of numbers:
Listing 4-12.
def sum_args(*nums):
return sum(nums)
Calling the function using a sequence of numbers:
85
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
>>> seq = [6,5,4,3]
>>> sum_args(*seq)
18
# we can also call the function without using the *
>>> sum_args(1,2,3,4)
10
Recursive Function Calls
It is also quite common to see cases in which a function calls itself from inside the function body. This
type of function call is known as a recursive function call. Let’s take a look at a function that computes
the factorial of a given argument. This function calls itself passing in the provided argument
decremented by 1 until the argument reaches the value of 0 or 1.
Listing 4-13.
def fact(n):
if n in (0, 1):
return 1
else:
return n * fact(n - 1)
It is important to note that Jython is like CPython in that it is ultimately stack based. Stacks are
regions of memory where data is added and removed in a last-in first-out manner. If a recursive function
calls itself too many times then it is possible to exhaust the stack, which results in an OutOfMemoryError.
Therefore, be cautious when developing software using deep recursion.
Function Body
This section will break down the different components that comprise the body of a function. The body of
a function is the part that performs the work. Throughout the next couple of sub-sections, you will see
that a function body can be comprised of many different parts.
Documenting Functions
First, you should specify a document string for the function. The docstring, if it exists, is a string that
occurs as the first value of the function body.
Listing 4-14.
def times2(n):
"""Given n, returns n * 2"""
return n * 2
As mentioned in Chapter 1, by convention we use triple-quoted strings, even if your docstring is not
multiline. If it is multiline, this is how we recommend you format it. For more information, please take a
look at PEP 257 (www.python.org/dev/peps/pep-0257).
86
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
Listing 4-15.
def fact(n):
"""Returns the factorial of n
Computes the factorial of n recursively. Does not check its
arguments if nonnegative integer or if would stack
overflow. Use with care!
"""
if n in (0, 1):
return 1
else:
return n * fact(n - 1)
Any such docstring, but with leading indentation stripped, becomes the __doc__ attribute of that
function object. Incidentally, docstrings are also used for modules and classes, and they work exactly the
same way.
You can now use the help built-in function to get the docstring, or see them from various IDEs like
PyDev for Eclipse and nbPython for NetBeans as part of the auto-complete.
Listing 4-16.
>>> help(fact)
Help on function fact in module __main__:
fact(n)
Returns the factorial of n
>>>
Returning Values
All functions return some value. In times2, we use the return statement to exit the function with that
value. Functions can easily return multiple values at once by returning a tuple or other structure. The
following is a simple example of a function that returns more than one value. In this case, the tip
calculator returns the result of a tip based upon two percentage values.
Listing 4-17.
>>> def calc_tips(amount):
...
return (amount * .18), (amount * .20)
...
>>> calc_tips(25.25)
(4.545, 5.050000000000001)
A function can return at any time, and it can also return any object as its value. So you can have a
function that looks like the following:
87
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
Listing 4-18.
>>> def check_pos_perform_calc(num1, num2, func):
...
if num1 > 0 and num2 > 0:
...
return func(num1, num2)
...
else:
...
return 'Only positive numbers can be used with this function!'
...
>>> def mult_values(value1, value2):
...
return value1 * value2
...
>>> check_pos_perform_calc(3, 4, mult_values)
12
>>> check_pos_perform_calc(3, -44, mult_values)
'Only positive numbers can be used with this function!'
If a return statement is not used, the value None is returned. There is no equivalent to a void method
in Java, because every function in Python returns a value. However, the Python console will not show the
return value when it’s None, so you need to explicitly print it to see what is returned.
Listing 4-19.
>>> do_nothing()
>>> print do_nothing()
None
Introducing Variables
A function introduces a scope for new names, such as variables. Any names that are created in the
function are only visible within that scope. In the following example, the sq variable is defined within the
scope of the function definition itself. If we try to use it outside of the function then we’ll receive an
error.
Listing 4-20.
>>> def square_num(num):
...
""" Return the square of a number"""
...
sq = num * num
...
return sq
...
>>> square_num(35)
1225
>>> sq
Traceback (most recent call last):
File "", line 1, in
NameError: name 'sq' is not defined
88
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
GLOBAL VARIABLES
The global keyword is used to declare that a variable name is from the module scope (or script) containing
this function. Using global is rarely necessary in practice, since it is not necessary if the name is called as
a function or an attribute is accessed (through dotted notation).
This is a good example of where Python is providing a complex balancing between a complex idea—the
lexical scoping of names, and the operations on them—and the fact that in practice it is doing the right
thing.
Here is an example of using a global variable in the same square_num() function.
Listing 4-21.
>>>
>>>
...
...
...
...
>>>
100
>>>
100
sq = 0
def square_num(n):
global sq
sq = n * n
return sq
square_num(10)
sq
Other Statements
What can go in a function body? Pretty much any statement, including material that we will cover later
in this book. So you can define functions or classes or use even import, within the scope of that function.
In particular, performing a potentially expensive operation like import as least as possible, can
reduce the startup time of your app. It’s even possible it will be never needed too.
There are a couple of exceptions to this rule. In both cases, these statements must go at the
beginning of a module, similar to what we see in a static language like Java:
•
Compiler directives. Python supports a limited set of compiler directives that have
the provocative syntax of from __future__ import X; see PEP 236. These are
features that will eventually be made available, generally in the next minor
revision (such as 2.5 to 2.6). In addition, it’s a popular place to put Easter eggs,
such as from __future__ import braces. (Try it in the console, which also relaxes
what it means to be performed at the beginning.)
•
Source encoding declaration. Although technically not a statement—it’s in a
specially parsed comment—this must go in the first or second line.
Empty Functions
It is also possible to define an empty function. Why have a function that does nothing? As in math, it’s
useful to have an operation that stands for doing nothing, like “add zero” or “multiply by one.” These
identity functions eliminate special cases. Likewise, as see with empty_callback, we may need to specify
a callback function when calling an API, but nothing actually needs to be done. By passing in an empty
89
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
function—or having this be the default—we can simplify the API. An empty function still needs
something in its body. You can use the pass statement.
Listing 4-22.
def do_nothing():
pass # here's how to specify an empty body of code
Or you can just have a docstring for the function body as in the following example.
def empty_callback(*args, **kwargs):
"""Use this function where we need to supply a callback,
but have nothing further to do.
"""
Miscellaneous Information for the Curious Reader
As you already know, Jython is an interpreted language. That is, the Python code that we write for a
Jython application is ultimately compiled down into Java bytecode when our program is run. So
oftentimes it is useful for Jython developers to understand what is going on when this code is interpreted
into Java bytecode.
What do functions look like from Java? They are instances of an object named PyObject, supporting
the __call__ method.
Additional introspection is available. If a function object is just a standard function written in
Python, it will be of class PyFunction. A built-in function will be of class PyBuiltinFunction. But don’t
assume that in your code, because many other objects support the function interface (__call__), and
these potentially could be proxying, perhaps several layers deep, a given function. You can only assume
it’s a PyObject.
Much more information is available by going to the Jython wiki. You can also send questions to the
jython-dev mailing list for more specifics.
Built-in Functions
Built-in functions are those functions that are always in the Python namespace. In other words, these
functions—and built-in exceptions, boolean values, and some other objects—are the only truly globally
defined names. If you are familiar with Java, they are somewhat like the classes from java.lang.
Built-ins are rarely sufficient, however; even a simple command line script generally needs to parse
its arguments or read in from its standard input. So for this case you would need to import sys. And in
the context of Jython, you will need to import the relevant Java classes you are using, perhaps with
import java. But the built-in functions are really the core function that almost all Python code uses.
The documentation for covering all of the built-in functions that are available is extensive. However,
it has been included in this book as Appendix C. It should be easy to use Appendix C as a reference when
using a built-in function, or for choosing which built-in function to use.
Alternative Ways to Define Functions
The ‘def’ keyword is not the only way to define a function. Here are some alternatives:
•
Lambda Functions: ‘lambda’ functions. The ‘lambda’ keyword creates an
unnamed function. Some people like this because it requires minimal space,
especially when used in a callback.
90
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
•
Classes: In addition, we can also create objects with classes whose instance
objects look like ordinary functions. Objects supporting the __call__ protocol. For
Java developers, this is familiar. Classes implement such single-method interfaces
as Callable or Runnable.
•
Bound Methods: Instead of calling x.a(), I can pass x.a as a parameter or bind to
another name. Then I can invoke this name. The first parameter of the method
will be passed the bound object, which in OO terms is the receiver of the method.
This is a simple way of creating callbacks. (In Java you would have just passed the
object of course, then having the callback invoke the appropriate method such as
call or run.)
Lambda Functions
As stated in the introduction, a lambda function is an anonymous function. In other words, a lambda
function is not required to be bound to any name. This can be useful when you are trying to create
compact code or when it does not make sense to declare a named function because it will only be used
once.
A lambda function is usually written inline with other code, and most often the body of a lambda
function is very short in nature. A lambda function is comprised of the following segments:
lambda <> : <>
A lambda function accepts arguments just like any other function, and it uses those arguments
within its function body. Also, just like other functions in Python a value is always returned. Let’s take a
look at a simple lambda function to get a better understanding of how they work.
Listing 4-23. Example of using a lambda function to combine two strings. In this case, a first and last
name
>>> name_combo = lambda first,last: first + ' ' + last
>>> name_combo('Jim','Baker')
'Jim Baker'
In the example above, we assigned the function to a name. However, a lambda function can also be
defined in-line with other code. Oftentimes a lambda function is used within the context of other
functions, namely built-ins.
Generator Functions
Generators are special functions that are an example of iterators, which will be discussed in Chapter 6.
Generators advance to the next point by calling the special method next. Usually that’s done implicitly,
typically through a loop or a consuming function that accepts iterators, including generators. They
return values by using the yield statement. Each time a yield statement is encountered then the current
iteration halts and a value is returned. Generators have the ability to remember where they left off. Each
time next() is called, the generator resumes where it had left off. A StopIteration error will be raised once
the generator has been terminated.
Over the next couple of sections, we will take a closer look at generators and how they work. Along
the way, you will see many examples for creating and using generators.
91
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
Defining Generators
A generator function is written so that it consists of one or more yield points, which are marked through
the use of the yield statement. As mentioned previously, each time the yield statement is encountered, a
value is returned.
Listing 4-24.
def g():
print
# The
yield
print
yield
yield
"before yield point 1"
generator will return a value once it encounters the yield statement
1
"after 1, before 2"
2
3
In the previous example, the generator function g() will halt and return a value once the first yield
statement is encountered. In this case, a 1 will be returned. The next time g.next() is called, the generator
will continue until it encounters the next yield statement. At that point it will return another value, the 2
in this case. Let’s see this generator in action. Note that calling the generator function simply creates
your generator, it does not cause any yields. In order to get the value from the first yield, we must call
next().
Listing 4-25.
# Call the function to create the generator
>>> x = g()
# Call next() to get the value from the yield
>>> x.next()
before the yield point 1
1
>>> x.next()
after 1, before 2
2
>>> x.next()
3
>>> x.next()
Traceback (most recent call last):
File "", line 1, in
StopIteration
Let’s take a look at another more useful example of a generator. In the following example, the
step_to() function is a generator that increments based upon a given factor. The generator starts at zero
and increments each time next() is called. It will stop working once it reaches the value that is provided
by the stop argument.
Listing 4-26.
>>> def step_to(factor, stop):
...
step = factor
...
start = 0
92
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
...
while start <= stop:
...
yield start
...
start += step
...
>>> for x in step_to(1, 10):
...
print x
...
0
1
2
3
4
5
6
7
8
9
10
>>> for x in step_to(2, 10):
...
print x
...
0
2
4
6
8
10
>>>
If the yield statement is seen in the scope of a function, then that function is compiled as if it’s a
generator function. Unlike other functions, you use the return statement only to say, “I’m done,” that is,
to exit the generator, and not to return any values. You can think of return as acting like a break in a forloop or while-loop. Let’s change the step_to function just a bit to check and ensure that the factor is less
than the stopping point. We’ll add a return statement to exit the generator if the factor is greater or equal
to the stop.
Listing 4-27
>>> def step_return(factor, stop):
...
step = factor
...
start = 0
...
if factor >= stop:
...
return
...
while start <= stop:
...
yield start
...
start += step
...
>>> for x in step_return(1,10):
...
print x
...
0
1
2
93
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
3
4
5
6
7
8
9
10
>>> for x in step_return(3,10):
...
print x
...
0
3
6
9
>>> for x in step_return(3,3):
...
print x
...
If you attempt to return an argument then a syntax error will be raised.
Listing 4-28.
def g():
yield 1
yield 2
return None
for i in g():
print i
SyntaxError: 'return' with argument inside generator
Many useful generators actually will have an infinite loop around their yield expression, instead of
ever exiting, explicitly or not. The generator will essentially work each time next() is called throughout
the life of the program.
Listing 4-29. Pseudocode for generator using infinite loop
while True:
yield stuff
This works because a generator object can be garbage collected as soon as the last reference to the
generator is used. The fact that it uses the machinery of function objects to implement itself doesn’t
matter.
HOW IT ACTUALLY WORKS
Generators are actually compiled differently from other functions. Each yield point saves the state of
unnamed local variables (Java temporaries) into the frame object, then returns the value to the function
94
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
that had called next (or send in the case of a coroutine which will be discussed later in this chapter). The
generator is then indefinitely suspended, just like any other iterator. Upon calling next again, the generator
is resumed by restoring these local variables, then executing the next bytecode instruction following the
yield point. This process continues until the generator is either garbage collected or it exits.
Generators can also be resumed from any thread, although some care is necessary to ensure that
underlying system state is shared (or compatible).
Generator Expressions
Generator expressions are an alternative way to create the generator object. Please note that this is not
the same as a generator function! It’s the equivalent to what a generator function yields when called.
Generator expressions basically create an unnamed generator.
Listing 4-30.
>>> x = (2 * x for x in [1,2,3,4])
>>> x
>>> x()
Traceback (most recent call last):
File "", line 1, in
TypeError: 'generator' object is not callable
Let’s see this generator expression in action:
>>> for v in x:
...
print v
...
2
4
6
8
>>>
Typically generator expressions tend to be more compact but less versatile than generator
functions. They are useful for getting things done in a concise manner.
Namespaces, Nested Scopes, and Closures
Note that you can introduce other namespaces into your function definition. It is possible to include
import statements directly within the body of a function. This allows such imports to be valid only
within the context of the function. For instance, in the following function definition the imports of A and
B are only valid within the context of f().
Listing 4-31.
def f():
from NS import A, B
At first glance, including import statements within your function definitions may seem unnecessary.
However, if you think of a function as an object then it makes much more sense. We can pass functions
95
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
around just like other objects in Python such as variables. As mentioned previously, functions can even
be passed to other functions as arguments. Function namespaces provide the ability to treat functions as
their own separate piece of code. Oftentimes, functions that are used in several different places
throughout an application are stored in a separate module. The module is then imported into the
program where needed.
Functions can also be nested within each other to create useful solutions. Since functions have their
own namespace, any function that is defined within another function is only valid within the parent
function. Let’s take a look at a simple example of this before we go any further.
Listing 4-32.
>>>
...
...
...
...
...
…
>>>
>>>
1
>>>
2
>>>
3
>>>
4
def parent_function():
x = [0]
def child_function():
x[0] += 1
return x[0]
return child_function
p = parent_function()
p()
p()
p()
p()
While this example is not extremely useful, it allows you to understand a few of the concepts for
nesting functions. As you can see, the parent_function contains a function named child_function. The
parent_function in this example returns the child_function. What we have created in this example is a
simple Closure function. Each time the function is called, it executes the inner function and increments
the variable x which is only available within the scope of this closure.
In the context of Jython, using closures such as the one defined previously can be useful for
integrating Java concepts as well. It is possible to import Java classes into the scope of your function just
as it is possible to work with other Python modules. It is sometimes useful to import in a function call in
order to avoid circular imports, which is the case when function A imports function B, which in turn
contains an import to function A. By specifying an import in a function call you are only using the
import where it is needed. You will learn more about using Java within Jython in Chapter 10.
Function Decorators
Decorators are a convenient syntax that describes a way to transform a function. They are essentially a
metaprogramming technique that enhances the action of the function that they decorate. To program a
function decorator, a function that has already been defined can be used to decorate another function,
which basically allows the decorated function to be passed into the function that is named in the
decorator. Let’s look at a simple example.
96
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
Listing 4-33.
def plus_five(func):
x = func()
return x + 5
@plus_five
def add_nums():
return 1 + 2
In this example, the add_nums() function is decorated with the plus_five() function. This has the
same effect as passing the add_nums function into the plus_five function. In other words, this decorator
is syntactic sugar that makes this technique easier to use. The decorator above has the same
functionality as the following code.
Listing 4-34.
add_nums = plus_five(add_nums)
In actuality, add_nums is now no longer a function, but rather an integer. After decorating with
plus_five you can no longer call add_nums(), we can only reference it as if it were an integer. As you can
see, add_nums is being passed to plus_five at import time. Normally, we’d want to have add_nums finish
up as a function so that it is still callable. In order to make this example more useful, we’ll want to make
add_nums callable again and we will also want the ability to change the numbers that are added. To do
so, we need to rewrite the decorator function a bit so that it includes an inner function that accepts
arguments from the decorated function.
Listing 4-35.
def plus_five(func):
def inner(*args, **kwargs):
x = func(*args, **kwargs) + 5
return x
return inner
@plus_five
def add_nums(num1, num2):
return num1 + num2
Now we can call the add_nums() function once again and we can also pass two arguments to it.
Because it is decorated with the plus_five function it will be passed to it and then the two arguments will
be added together and the number five will be added to that sum. The result will then be returned.
Listing 4-36.
>>> add_nums(2,3)
10
>>> add_nums(2,6)
13
97
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
Now that we’ve covered the basics of function decorators it is time to take a look at a more in-depth
example of the concept. In the following decorator function example, we are taking a twist on the old
tip_calculator function and adding a sales tax calculation. As you see, the original calc_bill function takes
a sequence of amounts, namely the amounts for each item on the bill. The calc_bill function then simply
sums the amounts and returns the value. In the given example, we apply the sales_tax decorator to the
function which then transforms the function so that it not only calculates and returns the sum of all
amounts on the bill, but it also applies a standard sales tax to the bill and returns the tax amount and
total amounts as well.
Listing 4-37.
def sales_tax(func):
''' Applies a sales tax to a given bill calculator '''
def calc_tax(*args, **kwargs):
f = func(*args, **kwargs)
tax = f * .18
print "Total before tax: $ %.2f" % (f)
print "Tax Amount: $ %.2f" % (tax)
print "Total bill: $ %.2f" % (f + tax)
return calc_tax
@sales_tax
def calc_bill(amounts):
''' Takes a sequence of amounts and returns sum '''
return sum(amounts)
The decorator function contains an inner function that accepts two arguments, a sequence of
arguments and a dictionary of keyword args. We must pass these arguments to our original function
when calling from the decorator to ensure that the arguments that we passed to the original function are
applied within the decorator function as well. In this case, we want to pass a sequence of amounts to
calc_bill, so passing the *args, and **kwargs arguments to the function ensures that our amounts
sequence is passed within the decorator. The decorator function then performs simple calculations for
the tax and total dollar amounts and prints the results. Let’s see this in action:
Listing 4-38.
>>> amounts = [12.95,14.57,9.96]
>>> calc_bill(amounts)
Total before tax: $ 37.48
Tax Amount: $ 6.75
Total bill: $ 44.23
It is also possible to pass arguments to decorator functions when doing the decorating. In order to
do so, we must nest another function within our decorator function. The outer function will accept the
arguments to be passed into the decorator function, the inner function will accept the decorated
function, and the inner most function will perform the work. We’ll take another spin on the tip
calculator example and create a decorator that will apply the tip calculation to the calc_bill function.
Listing 4-39.
def tip_amount(tip_pct):
def calc_tip_wrapper(func):
98
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
def calc_tip_impl(*args, **kwargs):
f = func(*args, **kwargs)
print "Total bill before tip: $ %.2f" % (f)
print "Tip amount: $ %.2f" % (f * tip_pct)
print "Total with tip: $ %.2f" % (f + (f * tip_pct))
return calc_tip_impl
return calc_tip_wrapper
Now let’s see this decorator function in action. As you’ll notice, we pass a percentage amount to the
decorator itself and it is applied to the decorator function.
Listing 4-40.
>>> @tip_amount(.18)
... def calc_bill(amounts):
...
''' Takes a sequence of amounts and returns sum '''
...
return sum(amounts)
...
>>> amounts = [20.95, 3.25, 10.75]
>>> calc_bill(amounts)
Total bill before tip: $ 34.95
Tip amount: $ 6.29
Total with tip: $ 41.24
As you can see, we have a similar result as was produced with the sales tax calculator, except that
with this decorator solution we can now vary the tip percentage. All of the amounts in the sequence of
amounts are summed up and then the tip is applied. Let’s take a quick look at what is actually going on if
we do not use the decorator @ syntax.
Listing 4-41.
calc_bill = tip_amount(.18)(calc_bill)
At import time, the tip_amount() function takes both the tip percentage and the calc_bill function as
arguments, and the result becomes the new calc_bill function. By including the decorator, we’re
actually decorating calc_bill with the function which is returned by tip_amount(.18). In the larger scale
of the things, if we applied this decorator solution to a complete application then we could accept the tip
percentage from the keyboard and pass it into the decorator as we’ve shown in the example. The tip
amount would then become a variable that can fluctuate based upon a different situation. Lastly, if we
were dealing with a more complex decorator function, we have the ability to change the inner-working
of the function without adjusting the original decorated function at all. Decorators are an easy way to
make our code more versatile and manageable.
Coroutines
Coroutines are often compared to generator functions in that they also make use of the yield statement.
However, a coroutine is exactly the opposite of a generator in terms of functionality. A coroutine actually
treats a yield statement as an expression, and it accepts data instead of returning it. Coroutines are
oftentimes overlooked as they may at first seem like a daunting topic. However, once it is understood
that coroutines and generators are not the same thing then the concept of how they work is a bit easier
to grasp.
99
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
A coroutine is a function that receives data and does something with it. We will take a look at a
simple coroutine example and then break it down to study the functionality.
Listing 4-42.
def co_example(name):
print 'Entering coroutine %s' % (name)
my_text = []
while True:
txt = (yield)
my_text.append(txt)
print my_text
Here we have a very simplistic coroutine example. It accepts a value as the “name” of the coroutine.
It then accepts strings of text, and each time a string of text is sent to the coroutine, it is appended to a
list. The yield statement is the point where text is being entered by the user. It is assigned to the txt
variable and then processing continues. It is important to note that the my_text list is held in memory
throughout the life of the coroutine. This allows us to append values to the list with each yield. Let’s take
a look at how to actually use the coroutine.
Listing 4-43.
>>> ex = co_example("example1")
>>> ex.next()
Entering coroutine example1
In this code, we assign the name “example1” to this coroutine. We could actually accept any type of
argument for the coroutine and do whatever we want with it. We’ll see a better example after we
understand how this works. Moreover, we could assign this coroutine to multiple variables of different
names and each would then be its own coroutine object that would function independently of the
others. The next line of code calls next() on the function. The next() must be called once to initialize the
coroutine. Once this has been done, the function is ready to accept values.
Listing 4-44.
>>> ex.send("test1")
['test1']
>>> ex.send("test2")
['test1', 'test2']
>>> ex.send("test3")
['test1', 'test2', 'test3']
As you can see, we use the send() method to actually send data values into the coroutine. In the
function itself, the text we send is inserted where the (yield) expression is placed. We can really continue
to use the coroutine forever, or until our JVM is out of memory. However, it is a best practice to close()
the coroutine once it is no longer needed. The close() call will cause the coroutine to be garbage
collected.
100
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
Listing 4-45.
>>> ex.close()
>>> ex.send("test1")
Traceback (most recent call last):
File "", line 1, in
StopIteration
If we try to send more data to the function once it has been closed then a StopIteration error is
raised. Coroutines can be very helpful in a number of situations. While the previous example doesn’t do
much, there are a number of great applications to which we can apply the use of coroutines and we will
see a more useful example in a later section.
Decorators in Coroutines
While the initialization of a coroutine by calling the next() method is not difficult to do, we can eliminate
this step to help make things even easier. By applying a decorator function to our coroutine, we can
automatically initialize it so it is ready to receive data.
Let’s define a decorator that we can apply to the coroutine in order to make the call to next().
Listing 4-46.
def coroutine_next(f):
def initialize(*args,**kwargs):
coroutine = f(*args,**kwargs)
coroutine.next()
return coroutine
return initialize
Now we will apply our decorator to the coroutine function and then make use of it.
>>> @coroutine_next
... def co_example(name):
...
print 'Entering coroutine %s' % (name)
...
my_text = []
...
while True:
...
txt = (yield)
...
my_text.append(txt)
...
print my_text
...
>>> ex2 = co_example("example2")
Entering coroutine example2
>>> ex2.send("one")
['one']
>>> ex2.send("two")
['one', 'two']
>>> ex2.close()
As you can see, while it is not necessary to use a decorator for performing such tasks, it definitely
makes things easier to use. If we chose not to use the syntactic sugar of the @ syntax, we could do the
following to initialize our coroutine with the coroutine_next() function.
101
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
Listing 4-47.
co_example = coroutine_next(co_example)
Coroutine Example
Now that we understand how coroutines are used, let’s take a look at a more in-depth example.
Hopefully after reviewing this example you will understand how useful such functionality can be.
In this example, we will pass the name of a file to the coroutine on initialization. After that, we will
send strings of text to the function and it will open the text file that we sent to it (given that the file
resides in the correct location), and search for the number of matches per a given word. The numeric
result for the number of matches will be returned to the user.
Listing 4-48.
def search_file(filename):
print 'Searching file %s' % (filename)
my_file = open(filename, 'r')
file_content = my_file.read()
my_file.close()
while True:
search_text = (yield)
search_result = file_content.count(search_text)
print 'Number of matches: %d' % (search_result)
The coroutine above opens the given file, reads its content, and then searches and returns the
number of matches for any given send call.
Listing 4-49.
>>> search = search_file("example4_3.txt")
>>> search.next()
Searching file example4_3.txt
>>> search.send('python')
Number of matches: 0
>>> search.send('Jython')
Number of matches: 1
>>> search.send('the')
Number of matches: 4
>>> search.send('This')
Number of matches: 2
>>> search.close();
Summary
In this chapter, we have covered the use of functions in the Python language. There are many different
use-cases for functions and we have learned techniques that will allow us to apply the functions to many
situations. Functions are first-class objects in Python, and they can be treated as any other object. We
started this chapter by learning the basics of how to define a function. After learning about the basics, we
102
www.it-ebooks.info
CHAPTER 4 ■ DEFINING FUNCTIONS AND USING BUILT-INS
began to evolve our knowledge of functions by learning how to use parameters and make recursive
function calls.
There are a wide variety of built-in functions available for use. If you take a look at Appendix C of
this book you can see a listing of these built-ins. It is a good idea to become familiar with what built-ins
are available. After all, it doesn’t make much sense to rewrite something that has already been written.
This chapter also discussed some alternative ways to define functions including the lambda
notation, as well as some alternative types of functions including decorators, generators and coroutines.
Wrapping up this chapter, you should now be familiar with Python functions and how to create and use
them. You should also be familiar with some of the advanced techniques that can be applied to
functions.
In the next chapter, you will learn a bit about input and output with Jython and the basics of Python
I/O. Later in this book, we will build upon object-orientation and learn how to use classes in Python.
103
www.it-ebooks.info
www.it-ebooks.info
CHAPTER 5
■■■
Input and Output
A program means very little if it does not take input of some kind from the program user. Likewise, if
there is no form of output from a program then one may ask why we have a program at all. Input and
output operations can define the user experience and usability of any program. This chapter is all about
how to put information or data into a program, and then how to display it or save it to a file. This chapter
does not discuss working with databases, but rather, working at a more rudimentary level with files.
Throughout this chapter you will learn such techniques as how to input data for a program via a
terminal or command line, likewise, you will learn how to read input from a file and write to a file. After
reading this chapter, you should know how to persist Python objects to disk using the pickle module and
also how to retrieve objects from disk and use them.
Input from the Keyboard
As stated, almost every program takes input from a user in one form or another. Most basic applications
allow for keyboard entry via a terminal or command line environment. Python makes keyboard input
easy, and as with many other techniques in Python there are more than one way to enable keyboard
input. In this section, we’ll cover each of those different ways to perform this task, along with a couple of
use-cases. In the end you should be able to identify the most suitable method of performing input and
output for your needs.
sys.stdin and raw_input
Making use of std.stdin is by far the most widely used method to read input from the command line or
terminal. This procedure consists of importing the sys package, then writing a message prompting the
user for some input, and lastly reading the input by making a call to sys.stdin.readln() and assigning the
returned value to a variable. The process looks like the code that is displayed in Listing 5-1.
Listing 5-1. Using sys.stdin
# Obtain a value from the command line and store it into a variable
>>> import sys
>>> fav_team = sys.stdin.readline()
Cubs
>>> sys.stdout.write("My favorite team is: %s" % fav_team)
My favorite team is: Cubs
You can see that the usage of sys modules is quite easy. However, another approach to performing this
same task is to make use of the raw_input function. This function uses a more simplistic syntax in order
105
www.it-ebooks.info
CHAPTER 5 ■ INPUT AND OUTPUT
to perform the same procedure. It basically generates some text on the command line or terminal,
accepts user input, and assigns it to a variable. Let’s take a look at the same example from above using
the raw_input syntax. Note that there is another function that performs a similar task named the input
function. However, the input function needs to be used with great care as it could be a potential security
risk. The raw_input function always returns content passed in as a string whereas the input function
returns content and evaluates it as an expression. It is safest to stay away from using input whenever
possible.
Listing 5-2. Using raw_input
# Obtain a value using raw_input and store it into a variable
>>> fav_team = raw_input("Enter your favorite team: ")
Enter your favorite team: Cubs
Obtaining Variables from Jython Environment
It is possible to retrieve values directly from the Jython environment for use within your applications.
For instance, we can obtain system environment variables or the strings that have been passed into the
command line or terminal when running the program.
To use environment variable values within your Jython application, simply import the os module and
use it’s environ dictionary to access them. Since this is a dictionary object, you can obtain a listing of all
environment variables by simply typing os.environ.
Listing 5-3. Obtaining and Altering System Environment Variables
>>> import os
>>> os.environ["HOME"]
'/Users/juneau'
# Change home directory for the Python session
>>> os.environ["HOME"] = "/newhome"
>>> os.environ["HOME"]
/newhome'
When you are executing a Jython module from the command prompt or terminal, you can make use
of the sys.argv list that takes values from the command prompt or terminal after invoking the Jython
module. For instance, if we are interested in having our program user enter some arguments to be used
by the module, they can simply invoke the module and then type all of the text entries followed by
spaces, using quotes if you wish to pass an argument that contains a space. The number of arguments
can be any size (I’ve never hit an upper bound anyways), so the possibilities are endless.
Listing 5-4. Using sys.argv
# sysargv_print.py – Prints all of the arguments provided at the command line
import sys
for sysargs in sys.argv:
print sysargs
# Usage
>>> jython sysargv_print.py test test2 "test three"
sysargv_print.py
test
test2
106
www.it-ebooks.info
CHAPTER 5 ■ INPUT AND OUTPUT
test three
As you can see, the first entry in sys.argv is the script name, and then each additional argument
provided after the module name is then added to the sys.argv list. This is quite useful for creating scripts
to use for automating tasks, etc.
File I/O
You learned a bit about the File data type in Chapter 2. In that chapter, we briefly discussed a few of the
operations that can be performed using this type. In this section, we will go into detail on what we can
do with a File object. We’ll start with the basics, and move into more detail. To begin, you should take a
look at Table 5-1 that lists all of the methods available to a File object and what they do.
Table 5-1. File Object Methods
Method
Description
close()
Close file
fileno()
Returns integer file descriptor
flush()
Used to flush or clear the output buffers and write content to the file
isatty()
If the file is an interactive terminal, returns 1
next()
This allows the file to be iterated over. Returns the next line in the file. If no line is
found, raises StopIteration
read(x)
Reads x bytes
readline(x)
Reads single line up to x characters, or entire line if x is omitted
readlines(size)
Reads all lines in file into a list. If size > 0, reads that number of characters
seek()
Moves cursor to a new position in the file
tell()
Returns the current position of the cursor
truncate(size)
Truncates file’s size. Size defaults to current position unless specified
write(string)
Writes a string to the file object
writelines(seq)
Writes all strings contained in a sequence with no separator
We’ll start by creating a file for use. As discussed in Chapter 2, the open(filename[, mode]) built-in
function creates and opens a specified file in a particular manner. The mode specifies what mode we will
open the file into, be it read, read-write, and so on.
107
www.it-ebooks.info
CHAPTER 5 ■ INPUT AND OUTPUT
Listing 5-5. Creating, Opening, and Writing to a File
>>>
>>>
>>>
>>>
my_file = open('mynewfile.txt','w')
first_string = "This is the first line of text."
my_file.write(first_string)
my_file.close()
In this example, the file “mynewfile.txt” did not exist until the open function was called. If it did exist
already, the previous version is overwritten by the new version and it is now empty. The file was created
in write mode and then we do just that, write a string to the file. Now, it is important to make mention
that the first_string is not actually written to the file until it is closed or flush() is performed. It is also
worth mentioning that if we were to close the file, reopen it, and perform a subsequent write() operation
on the file then the previous contents of the file would be overwritten by content of the new write.
Now we’ll step through each of the file functions in an example. The main focus of this example is to
provide you with a place to look for actual working file I/O code.
Listing 5-6.
# Write lines to file, flush, and close
>>> my_file = open('mynewfile.txt','w')
>>> my_file.write('This is the first line of text.\n')
>>> my_file.write('This is the second line of text.\n')
>>> my_file.write('This is the last line of text.\n')
>>> my_file.flush() # Optional, really unneccesary if closing the file but useful to clear
>>>
#buffer
>>> my_file.close()
# Open file in read mode
>>> my_file = open('mynewfile.txt','r')
>>> my_file.read()
'This is the first line of text.\nThis is the second line of text.\nThis is the last line of
text.\n'
# If we read again, we get a '' because cursor is at the end of text
>>> my_file.read()
''
# Seek back to the beginning of file and perform read again
>>> my_file.seek(0)
>>> my_file.read()
'This is the first line of text.This is the second line of text.This is the last line of
text.'
# Seek back to beginning of file and perform readline()
>>> my_file.seek(0)
>>> my_file.readline()
'This is the first line of text.\n'
>>> my_file.readline()
'This is the second line of text.\n'
>>> my_file.readline()
'This is the last line of text.\n'
>>> my_file.readline()
''
108
www.it-ebooks.info
CHAPTER 5 ■ INPUT AND OUTPUT
# Use tell() to display current cursor position
>>> my_file.tell()
93L
>>> my_file.seek(0)
>>> my_file.tell()
0L
# Loop through lines of file
>>> for line in my_file:
...
print line
...
This is the first line of text.
This is the second line of text.
This is the last line of text.
There are a handful of read-only attributes that we can use to find out more information about file
objects. For instance, if we are working with a file and want to see if it is still open or if it has been closed,
we could view the closed attribute on the file to return a boolean stating whether the file is closed. Table
5-2 lists each of these attributes and what they tell us about a file object.
Table 5-2. File Attributes
Attribute
Description
closed
Returns a boolean to indicate if the file is closed
encoding
Returns a string indicating encoding on file
mode
Returns the I/O mode for a file(i.e., ‘r’, ‘w’, ‘r+,’rb’, etc.)
name
Returns the name of the file
newlines
Returns the newline representation in the file. This keeps track of the types of newlines
encountered while reading the file. Allows for universal newline support.
Listing 5-7. File Attribute Usage
>>> my_file.closed
False
>>> my_file.mode
'r'
>>> my_file.name
'mynewfile.txt'
109
www.it-ebooks.info
CHAPTER 5 ■ INPUT AND OUTPUT
Pickle
One of the most popular modules in the Python language is the pickle module. The goal of this module is
basically to allow for the serialization and persistence of Python objects to disk in file format. A pickled
object can be written to disk using this module, and it can also be read back in and utilized in object
format. Just about any Python object can be persisted using pickle.
To write an object to disk, we call the pickle() function. The object will be written to file in a format
that may be unusable by anything else, but we can then read that file back into our program and use the
object as it was prior to writing it out. In the following example, we’ll create a Player object and then
persist it to file using pickle. Later, we will read it back into a program and make use of it. We will make
use of the File object when working with the pickle module.
Listing 5-8. Write an Object to Disk Using Pickle
>>>
>>>
...
...
...
...
...
>>>
>>>
>>>
>>>
import pickle
class Player(object):
def __init__(self, first, last, position):
self.first = first
self.last = last
self.position = position
player = Player('Josh','Juneau','Forward')
pickle_file = open('myPlayer','wb')
pickle.dump(player, pickle_file)
pickle_file.close()
In the example above, we’ve persisted a Player object to disk using the dump(object, file) method in
the pickle module. Now let’s read the object back into our program and print it out.
Listing 5-9. Read and Use a Pickled Object
>>> pickle_file = open('myPlayer','rb')
>>> player1 = pickle.load(pickle_file)
>>> pickle_file.close()
>>> player1.first
'Josh'
>>> player1.last, player1.position
('Juneau', 'Forward')
Similarly, we read the pickled file back into our program using the load(file) method. Once read and
stored into a variable, we can close the file and work with the object. If we had to perform a sequence of
dump or load tasks, we could do so one after the other without issue. You should also be aware that
there are different pickle protocols that can be used in order to make pickle work in different Python
environments. The default protocol is 0, but protocols 1 and 2 are also available for use. It is best to stick
with the default as it works well in most situations, but if you run into any trouble using pickle with
binary formats then please give the others a try.
If we had to store objects to disk and reference them at a later time, it may make sense to use the
shelve module which acts like a dictionary for pickled objects. With the shelve technique, you basically
pickle an object and store it using a string-based key value. You can later retrieve the object by passing
the key to the opened file object. This technique is very similar to a filing cabinet for our objects in that
we can always reference our objects by key value. Let’s take a look at this technique and see how it
works.
110
www.it-ebooks.info
CHAPTER 5 ■ INPUT AND OUTPUT
Listing 5-10. Using the Shelve Technique
# Store different player objects
>>> import shelve
>>> player1 = Player('Josh','Juneau','forward')
>>> player2 = Player('Jim','Baker','defense')
>>> player3 = Player('Frank','Wierzbicki','forward')
>>> player4 = Player('Leo','Soto','defense')
>>> player5 = Player('Vic','Ng','center')
>>> data = shelve.open("players")
>>> data['player1'] = player1
>>> data['player2'] = player2
>>> data['player3'] = player3
>>> data['player4'] = player4
>>> data['player5'] = player5
>>> player_temp = data['player3']
>>> player_temp.first, player_temp.last, player_temp.position
('Frank', 'Wierzbicki', 'forward')
>>> data.close()
In the scenario above, we used the same Player object that was defined in the previous examples.
We then opened a new shelve and named it “players”, this shelve actually consists of a set of three files
that are written to disk. These three files can be found on disk named “players.bak”, “players.dat”, and
“players.dir” once the objects were persisted into the shelve and when close() was called on the object.
As you can see, all of the Player objects we’ve instantiated have all been stored into this shelve unit, but
they exist under different keys. We could have named the keys however we wished, as long as they were
each unique. In the example, we persist five objects and then, at the end, one of the objects is retrieved
and displayed. This is quite a nice technique to make a small data store.
Output Techniques
We basically covered the print statement in Chapter 2 very briefly when discussing string formatting.
The print statement is by far the most utilized form of output in most Python programs. Although we
covered some basics such as conversion types and how to format a line of output in Chapter 2, here we
will go into a bit more depth on some different variations of the print statement as well as other
techniques for generating output. There are basically two formats that can be used with the print
statement. We covered the first in Chapter 2, and it makes use of a string and some conversion types
embedded within the string and preceded by a percent (%) symbol. After the string, we use another
percent(%) symbol followed by a parenthesized list of arguments that will be substituted in place of the
embedded conversion types in our string in order. Check out the examples of each depicted in the
example below.
Listing 5-11. Output With the Print Statement
# Using the % symbol
>>> x = 5
>>> y = 10
>>> print 'The sum of %d and %d is %d' % (x, y, (x + y))
The sum of 5 and 10 is 15
>>> adjective = "awesome"
>>> print 'Jython programming is %s' % (adjective)
111
www.it-ebooks.info
CHAPTER 5 ■ INPUT AND OUTPUT
Jython programming is awesome
You can also format floating-point output using the conversion types that are embedded in your
string. You may specify a number of decimal places you’d like to print by using a “.# of places” syntax in
the embedded conversion type.
Listing 5-12. Formatting Floating-Point Arithmetic
>>> pi = 3.14
>>> print 'Here is some formatted floating point arithmetic: %.2f' % (pi + y)
Here is some formatted floating point arithmetic: 13.14
>>> print 'Here is some formatted floating point arithmetic: %.3f' % (pi + y)
Here is some formatted floating point arithmetic: 13.140
Summary
It goes without saying that Python has its share of input and output strategies. This chapter covered
most of those techniques starting with basic terminal or command line I/O and then onto file
manipulation. We learned how to make use of the open function for creating, reading, or writing a file.
The command line sys.argv arguments are another way that we can grab input, and environment
variables can also be used from within our programs. Following those topics, we took a brief look at the
pickle module and how it can be used to persist Python objects to disk. The shelve module is another
twist on using pickle that allows for multiple objects to be indexed and stored within the same file.
Finally, we discussed a couple of techniques for performing output in our programs.
Although there are some details that were left out as I/O could consume an entire book, this chapter
was a solid starting point into the broad topic of I/O in Python. As with much of the Python language
specifics discussed in this book, there are many resources available on the web and in book format that
will help you delve deeper into the topics if you wish. A good resource is Beginning Python: From Novice
to Professional by: Magnus Lie Hetland. You may also wish to look at the Python documentation which
can be found at www.python.org/doc/.
112
www.it-ebooks.info
CHAPTER 6
■■■
Object-Oriented Jython
This chapter is going to cover the basics of object-oriented programming. We’ll start with covering the
basic reasons why you would want to write object-oriented code in the first place, and then cover all the
basic syntax, and finally we’ll show you a non-trivial example.
Object-oriented programming is a method of programming where you package your code up into
bundles of data and behavior. In Jython, you can define a template for this bundle with a class definition.
With this first class written, you can then create instances of that class that include instance-specific
data, as well as bits of code called methods that you can call to do things based on that data. This helps
you organize your code into smaller, more manageable bundles.
With the release of Jython 2.5, the differences in syntax between the C version of Python and Jython
are negligible. So, although everything here covers Jython, you can assume that all of the same code will
run on the C implementation of Python, as well. Enough introduction though—let’s take a look at some
basic syntax to see what this is all about.
Basic Syntax
Writing a class is simple. It is fundamentally about managing some kind of “state” and exposing some
functions to manipulate that state. In object jargon, we call those functions “methods.”
Let’s start by creating a Car class. The goal is to create an object that will manage its own location on
a two-dimensional plane. We want to be able to tell it to turn and move forward, and we want to be able
to interrogate the object to find out where its current location is. Place the following code in a file named
“car.py.”
Listing 6-1.
class Car(object):
NORTH = 0
EAST = 1
SOUTH = 2
WEST = 3
def __init__(self, x=0, y=0):
self.x = x
self.y = y
self.direction = self.NORTH
def turn_right(self):
self.direction += 1
self.direction = self.direction % 4
113
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
def turn_left(self):
self.direction -= 1
self.direction = self.direction % 4
def move(self, distance):
if self.direction == self.NORTH:
self.y += distance
elif self.direction == self.SOUTH:
self.y -= distance
elif self.direction == self.EAST:
self.x += distance
else:
self.x -= distance
def position(self):
return (self.x, self.y)
We’ll go over that class definition in detail but right now, let’s just see how to create a car, move it
around, and ask the car where it is.
Listing 6-2.
from car import Car
def test_car():
c = Car()
c.turn_right()
c.move(5)
assert (5, 0) ==
c.position()
c.turn_left()
c.move(3)
assert (5, 3) == c.position()
In Jython there are things that are “callables.” Functions are one kind of callable; classes are
another. So one way to think of a class is that it’s just a special kind of function, one that creates object
instances.
Once we’ve created the car instance, we can simply call functions that are attached to the Car class
and the object will manage its own location. From the point of view of our test code, we do not need to
manage the location of the car—nor do we need to manage the direction that the car is pointing in. We
just tell it to move, and it does the right thing.
Let’s go over the syntax in detail to see exactly what’s going on here.
In Line 1 of car.py, we declare that our Car object is a subclass of the root “object” class. Jython, like
many object-oriented languages, has a “root” object that all other objects are based off of. This “object”
class defines basic behavior that all classes can reuse.
Jython actually has two kinds of classes: “new style” and old style. The old way of declaring classes
didn’t require you to type “object;” you’ll occasionally see the old-style class usage in some Jython code,
but it’s not considered good practice. Just subclass “object” for any of your base classes and your life will
be simpler.
Lines 3 to 6 declare class attributes for the direction that any car can point to. These are class
attributes, so they can be shared across all object instances of the Car object. Class attributes can be
referenced without having to create an object instance.
114
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
Now for the good stuff.
Lines 8-11 declare the object initializer method. This method is called immediately after your object
is created and memory for it has been allocated. In some languages, you might be familiar with a
constructor; in Jython, we have an initializer which is run after construction. Valid method names in
Jython are similar to many other C style languages. Generally, use method names that start with a letter;
you can use numbers in the rest of the method name if you really want, but don’t use any spaces. Jython
classes have an assortment of special “magic” methods as well. These methods all start with a double
underscore and end with a double underscore. These methods are reserved by the language and they
have special meaning. So for our initializer “__init__,” the Jython runtime will automatically invoke that
method once you’ve called your constructor with “Car().” There are other reserved method names to let
you customize your classes further, and we’ll get into those later.
In our initializer, we are setting the initial position of the car to (0, 0) on a two-dimensional plane,
and then the direction of the car is initialized to pointing north. When we initialize the object, we don’t
have to pass in the position explicitly. The function signature uses Jython’s default argument list feature,
so we don’t have to explicitly set the initial location to (0,0). Default arguments for methods work just the
same as the default function arguments that were covered in Chapter 4. When the method is created,
Jython binds the default values into the method so that, if nothing is passed in, the signature’s values will
be used. There’s also a new argument introduced called “self.” This is a reference to the current object,
the Car object. If you’re familiar with other C style languages, you might have called the reference “this.”
Remember, your class definition is creating instances of objects. Once your object is created, it has
its own set of internal variables to manage. Your object will inevitably need to access these, as well as any
of the class internal methods. Jython will pass a reference to the current object as the first argument to
all your instance methods.
If you’re coming from some other object-oriented language, you’re probably familiar with the “this”
variable. Unlike C++ or Java, Jython doesn’t magically introduce the reference into the namespace of
accessible variables, but this is consistent with Jython’s philosophy of making things explicit for clarity.
When we want to assign the initial x, y position, we just need to assign values on to the name “x”,
and “y” on the object. Binding the values of x and y to self makes the position values accessible to any
code that has access to self; namely, the other methods of the object. One minor detail here: in Jython,
you can technically name the arguments however you want. There’s nothing stopping you from calling
the first argument “this” instead of “self,” but the community standard is to use “self.” One of Jython’s
strengths is its legibility and community standards around style.
Lines 13 to 19 declare two methods to turn the vehicle in different directions. Notice how the
direction is never directly manipulated by the caller of the Car object. We just asked the car to turn, and
the car changed its own internal “direction” state. In Jython, you can specify private attributes by using a
preceding double underscore, so self.direction would change to self.__direction. Once your object is
instantiated, your methods can continue to access private attributes using the double underscore name,
but external callers would not be able to easily access those private attributes. The attribute name will be
mangled for external callers into “obj._Car__direction”. In practice, we don’t suggest using private
attributes, because you cannot possibly know all the use cases your code may have to satisfy. If you want
to provide a hint to other programmers that an attribute should be considered private, you can use a
single underscore.
Lines 21 to 29 define where the car should move to when we move the car forward. The internal
direction variable informs the car how it should manipulate the x and y position. Notice how the caller of
the Car object never needs to know precisely what direction the car is pointing in. The caller only needs
to tell the object to turn and move forward. The particular details of how that message is used is
abstracted away.
That’s not too bad for a couple dozen lines of code.
This concept of hiding internal details is called encapsulation. This is a core concept in objectoriented programming. As you can see from even this simple example, it allows you to structure your
code so that you can provide a simplified interface to the users of your code.
115
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
Having a simplified interface means that we could have all kinds of behavior happening behind the
function calls to turn and move, but the caller can ignore all those details and concentrate on using the
car instead of managing the car.
As long as the method signatures don’t change, the caller really doesn’t need to care about any of
that.
Let’s extend the class definition now to add persistence so we can save and load the car’s state to
disk. The goal here is to add it without breaking the existing interface to our class.
First, pull in the pickle module. Pickle will let us convert Jython objects into byte strings that can be
restored to full objects later.
Import pickle
Now, just add two new methods to load and save the state of the object.
Listing 6-3.
def save(self, filename):
state = (self.direction, self.x, self.y)
pickle.dump(state, open(filename,'wb'))
def load(self, filename):
state = pickle.load(open(filename,'rb'))
(self.direction, self.x, self.y) = state
Simply add calls to save() at the end of the turn and move methods and the object will automatically
save all the relevant internal values to disk.
There’s a slight problem here: we need to have different files for each of our cars; our load and save
methods have explicit filename arguments but our objects themselves don’t have any notion of a name.
Let’s modify the intializer so that we always have a name bound into the object. Change __init__ to
accept a name argument.
Listing 6-4.
def __init__(self, name, x=0, y=0):
self.name = name
self.x = x
self.y = y
self.direction = self.NORTH
People who use the Car object don’t even need to know that it’s saving to disk, because the car
object handles it behind the scenes.
Listing 6-5.
def turn_right(self):
self.direction += 1
self.direction = self.direction % 4
self.save(self.name)
def turn_left(self):
self.direction -= 1
116
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
self.direction = self.direction % 4
self.save(self.name)
def move(self, distance):
if self.direction == self.NORTH:
self.y += distance
elif self.direction == self.SOUTH:
self.y -= distance
elif self.direction == self.EAST:
self.x += distance
else:
self.x -= distance
self.save(self.name)
Now, when you call the turn, or move methods, the car will automatically save itself to disk. If you
want to reconstruct the car object’s state from a previously saved pickle file, you can simply call the
load() method and pass in the string name of your car.
Object Attribute Lookups
If you’ve been paying attention, you’re probably wondering how the NORTH, SOUTH, EAST and WEST
variables got bound to self. We never actually assigned them to the self variable during object
initialization—so what’s going on when we call move()? How is Jython actually resolving the value of
those four variables?
Now seems like a good time to show how Jython resolves name lookups.
The direction names actually got bound to the car class. The Jython object system does a little bit of
magic when you try accessing any name against an object, it first searches for anything that was bound
to “self.” If Jython can’t resolve any attribute on self with that name, it goes up the object graph to the
class definition. The direction attributes NORTH, SOUTH, EAST, WEST were bound to the class
definition, so the name resolution succeeds and we get the value of the class attribute.
A very short example will help clarify this.
Listing 6-6.
>>> class Foobar(object):
...
def __init__(self):
...
self.somevar = 42
...
class_attr = 99
...
>>>
>>> obj = Foobar()
>>> obj.somevar
42
>>> obj.class_attr
99
>>> obj.not_there
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'Foobar' object has no attribute 'not_there'
>>>
117
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
So the key difference here is what you bind a value to. The values you bind to self are available only
to a single object. Values you bind to the class definition are available to all instances of the class. The
sharing of class attributes among all instances is a critical distinction, because mutating a class attribute
will affect all instances. This may cause unintended side effects if you’re not paying attention as a
variable may change value on you when you aren’t expecting it to.
Listing 6-7.
>>> other = Foobar()
>>> other.somevar
42
>>> other.class_attr
99
>>> # obj and other can have different values for somevar
>>> obj.somevar = 77
>>> obj.somevar
77
>>> other.somevar
42
>>> # If we assign to other.class_attr, that makes an instance attribute of other called
class_attr.
>>> other.class_attr = 66
>>> other.class_attr
66
>>> # And doesn't change the class_attribute class_attr for other objects
>>> obj.class_attr
99
>>> # You can still get at the class attribute from other by looking at
other.__class__.class_attr
>>> other.__class__.class_attr
99
>>> # and if you remove the instance attribute other.class_attr,
>>> then other.class_attr goes back to referring to the class attribute
>>> del other.class_attr
>>> other.class_attr
99
>>> # But if the class_attribute is mutable, when you change it, you change it for every
instance
>>> Foobar.class_list = []
>>> obj.class_list
[]
>>> other.class_list
[]
>>> obj.class_list.append(1)
118
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
>>> obj.class_list
[1]
>>> other.class_list
[1]
We think it’s important to stress just how transparent Jython’s object system really is. Object
attributes are just stored in a plain Jython dictionary. You can directly access this dictionary by looking
at the __dict__ attribute.
Listing 6-8.
>>> obj = Foobar()
>>> obj.__dict__
{'somevar': 42}
Notice that there are no references to the methods of the class (in this case, just our initializer), or
the class attribute ‘class_attr’. The __dict__ only shows the local attributes and methods of the object.
We’ll cover inheritance shortly, and you’ll see how attributes and methods are looked up in the case
where you specialize classes through subclassing.
The same trick can be used to inspect all the attributes of the class, just look into the __dict__
attribute of the class definition and you’ll find your class attributes and all the methods that are attached
to your class definition:
Listing 6-9.
>>> Foobar.__dict__
{'__module__': '__main__',
'class_attr': 99,
'__dict__': ,
'__init__': }
This transparency can be leveraged with dynamic programming techniques using closures and
binding new functions into your class definition at runtime. We’ll revisit this later in the chapter when
we look at generating functions dynamically and finally with a short introduction to metaprogramming.
Inheritance and Overloading
In the car example, we subclass from the root object type. You can also subclass your own classes to
specialize the behavior of your objects. You may want to do this if you notice that your code naturally
has a structure where you have many different classes that all share some common behavior.
With objects, you can write one class, and then reuse it using inheritance to automatically gain
access to the pre-existing behavior and attributes of the parent class. Your “base” objects will inherit
behavior from the root “object” class, but any subsequent subclasses will inherit from your own classes.
Let’s take a simple example of using some animal classes to see how this works. Define a module
“animals.py” with the following code:
119
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
Listing 6-10.
class Animal(object):
def sound(self):
return "I don't make any sounds"
class Goat(Animal):
def sound(self):
return "Bleeattt!"
class Rabbit(Animal):
def jump(self):
return "hippity hop hippity hop"
class Jackalope(Goat, Rabbit):
pass
Now you should be able to explore that module with the jython interpreter:
Listing 6-11.
>>> from animals import *
>>> animal = Animal()
>>> goat = Goat()
>>> rabbit = Rabbit()
>>> jack = Jackalope()
>>> animal.sound()
"I don't make any sounds"
>>> animal.jump()
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'Animal' object has no attribute 'jump'
>>> rabbit.sound()
"I don't make any sounds"
>>> rabbit.jump()
'hippity hop hippity hop'
>>> goat.sound()
'Bleeattt!'
>>> goat.jump()
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'Goat' object has no attribute 'jump'
>>> jack.jump()
'hippity hop hippity hop'
>>> jack.sound()
'Bleeattt!'
Inheritance is a very simple concept, when you declare your class, you simply specify which parent
classes you would like to reuse. Your new class can then automatically access all the methods and
attributes of the super class. In this example, the Goat object has no method jump, and its super class
Animal has no method jump, so the attempt to invoke the jump method fails. Invoking the sound
method on the rabbit actually calls the super class’s sound method.
This is the key idea: if an attribute lookup fails on the local object instance, the lookup is then
propagated up the inheritance tree to the super class. Notice how the Jackalope had access to methods
from both the rabbit and the goat because it can use two super classes to resolve methods.
120
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
With single inheritance—when your class simply inherits from one parent class—the rules for
resolving where to find an attribute or a method are very straightforward. Jython just looks up to the
parent if the current object doesn’t have a matching attribute.
It’s important to point out now that the Rabbit class is a type of Animal: the Jython runtime can tell
you that programmatically by using the isinstance function:
Listing 6-12.
>>> isinstance(bunny, Rabbit)
True
>>> isinstance(bunny, Animal)
True
>>> isinstance(bunny, Goat)
False
For many classes, you may want to extend the behavior of the parent class instead of just completely
overriding it. For this, you’ll want to use the super() function. Let’s specialize the Rabbit class like this:
Listing 6-13.
class EasterBunny(Rabbit):
def sound(self):
orig = super(EasterBunny, self).sound()
return "%s - but I have eggs!" % orig
If you now try making this rabbit speak, it will extend the original sound() method from the base
Rabbit class. Calling the super() function lets you access the super class’s implementation of the sound
method. In this example, it’s useful because the EasterBunny class is reusing and extending the basic
Rabbit class’s sound() method.
Listing 6-14.
>>> bunny = EasterBunny()
>>> bunny.sound()
"I don't make any sounds - but I have eggs!"
That wasn’t so bad. For these examples, we only demonstrated that inherited methods can be
invoked, but you can do exactly the same thing with attributes that are bound to the self.
For multiple inheritance, things get complicated quickly. Jython uses “left first, depth first” search to
resolve attribute lookups. In a nutshell, if you were to draw your inheritance diagram, Jython would look
down the left side of your graph looking for attributes going from the bottom up, left to right. If any
super class is inherited by two or more subclasses, then the super class is used for lookup only after all
attribute lookups have been exhausted on the subclasses.
Underscore Methods
Abstraction using plain classes is wonderful and all, but it’s even better if your code seems to naturally fit
into the syntax of the language. Jython supports a variety of underscore methods: methods that start and
end with double “_” signs that let you overload the behavior of your objects. This means that your
121
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
objects will seem to integrate more tightly with the language itself. You have already seen one such
method: __init__.
With the underscore methods, you can give you objects behavior for logical and mathematical
operations. You can even make your objects behave more like standard builtin types like lists, sets or
dictionaries. Let’s start with adding simple unicode extensions to a SimpleObject to see the most simple
example of this. Then we’ll move on to building customized container classes.
Listing 6-15.
from __future__ import with_statement
from contextlib import closing
with closing(open('simplefile','w')) as fout:
fout.writelines(["blah"])
with closing(open('simplefile','r')) as fin:
print fin.readlines()
This snippet of code just opens a file, writes a little bit of text, and then we read the contents out.
Not terribly exciting. Most objects in Jython are serializable to strings using the pickle module. The
pickle module lets us convert our live Jython objects into byte streams that can be saved to disk and later
restored into objects. Let’s see the functional version of this:
Listing 6-16.
from __future__ import with_statement
from contextlib import closing
from pickle import dumps, loads
def write_object(fout, obj):
data = dumps(obj)
fout.write("%020d" % len(data))
fout.write(data)
def read_object(fin):
length = int(fin.read(20))
obj = loads(fin.read(length))
return obj
class Simple(object):
def __init__(self, value):
self.value = value
def __unicode__(self):
return "Simple[%s]" % self.value
with closing(open('simplefile','wb')) as fout:
for i in range(10):
obj = Simple(i)
write_object(fout, obj)
print "Loading objects from disk!"
print '=' * 20
with closing(open('simplefile','rb')) as fin:
122
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
for i in range(10):
print read_object(fin)
This should output something like this:
Listing 6-17.
Loading objects from disk!
====================
Simple[0]
Simple[1]
Simple[2]
Simple[3]
Simple[4]
Simple[5]
Simple[6]
Simple[7]
Simple[8]
Simple[9]
So now we’re doing something interesting. Let’s look at exactly what happening here.
First, you’ll notice that the Simple object is rendering nicely: the Simple object can render itself
using the __unicode__ method. This is clearly an improvement over the earlier rendering of the object
with angle brackets and a hex code.
The write_object function is fairly straightforward, we’re just converting our objects into strings
using the pickle module, computing the length of the string and then writing the length and the actual
serialized object to disk.
This is fine, but the read side is a bit clunky. We don’t really know when to stop reading. We can fix
this using the iteration protocol. Which bring us to one of my favorite reasons to use objects at all in
Jython.
Protocols
In Jython, we have “duck typing.” If it walks like a duck, quacks like a duck, and looks like a duck, it’s a
duck. This is in stark contrast to more rigid languages like C# or Java which have formal interface
definitions. One of the nice benefits of having duck typing is that Jython has the notion of object
protocols.
If you happen to implement the right methods, Jython will recognize your object as a certain type of
‘thing’.
Iterators are objects that look like lists that let you read the next object. Implementing an iterator
protocol is straightforward: just implement a next() method and a __iter__ method, and you’re ready to
rock and roll. Let’s see this in action:
Listing 6-18.
class PickleStream(object):
"""
This stream can be used to stream objects off of a raw file stream
"""
def __init__(self, file):
self.file = file
123
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
def write(self, obj):
data = dumps(obj)
length = len(data)
self.file.write("%020d" % length)
self.file.write(data)
def __iter__(self):
return self
def next(self):
data = self.file.read(20)
if len(data) == 0:
raise StopIteration
length = int(data)
return loads(self.file.read(length))
def close(self):
self.file.close()
This class will let you wrap a simple file object and you can now send it raw Jython objects to write
to a file, or you can read objects out as if the stream was just a list of objects. Writing and reading
becomes much simpler:
Listing 6-19.
with closing(PickleStream(open('simplefile','wb'))) as stream:
for i in range(10):
obj = Simple(i)
stream.write(obj)
with closing(PickleStream(open('simplefile','rb'))) as stream:
for obj in stream:
print obj
Abstracting out the details of serialization into the PickleStream lets us “forget” about the details of
how we are writing to disk. All we care about is that the object will do the right thing when we call the
write() method.
The iteration protocol can be used for much more advanced purposes, but even with this example,
it should be obvious how useful it is. While you could implement the reading behavior with a read()
method, just using the stream as something you can loop over makes the code much easier to
understand.
Let’s step back now and look at some of the other underscore methods. Two of the most common
uses of underscore methods are to implement proxies and to implement your own container-like
classes. Proxies are very useful in many programming problems. You use a proxy to act as an
intermediary between a caller and a callee. The proxy class can add in extra behavior in a manner that is
transparent to the caller. In Jython, you can use the __getattr__ method to implement attribute lookups
if a method or attribute does not seem to exist.
124
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
Listing 6-20.
class SimpleProxy(object):
def __init__(self, parent):
self._parent = parent
def __getattr__(self, key):
return getattr(self._parent, key)
That represents the simplest (and not very useful) proxy. Any lookup for an attribute that doesn’t
exist on SimpleProxy will automatically invoke the __getattr__ method, and the lookup will then be
delegated to the parent object. Note that this works for attributes that are not underscore attributes.
Let’s look at a simple example to make this clearer.
Listing 6-21.
>>> class TownCrier(object):
...
def __init__(self, parent):
...
self._parent = parent
...
def __getattr__(self, key):
...
print "Accessing : [%s]" % key
...
return getattr(self._parent, key)
...
>>> class Calc(object):
...
def add(self, x, y):
...
return x + y
...
def sub(self, x, y):
...
return x – y
...
>>> calc = Calc()
>>> crier = TownCrier(calc)
>>> crier.add(5,6)
Accessing : [add]
11
>>> crier.sub(3,6)
Accessing : [sub]
-3
Here, we can see that our TownCrier class is delegating control to the Calculator object whenever a
method is invoked, but we are also adding in some debug messages along the way. Unlike a language
like Java where you would need to implement a specific interface (if one even exists), in Jython, creating
a proxy is nearly free. The __getattr__ method is automatically invoked if attribute lookups fail using the
normal lookup mechanism. Proxies provide a way for you to inject new behavior by using a delegation
pattern. The advantage here is that you can add new behavior without having to know anything about
the delegate’s implementation; something that you’d have to deal with if you used subclassing.
The second common use of underscore methods we’ll cover is implementing your own container
class. We’ll take a look at implementing a small dictionary-like class. Suppose we have class that behaves
like a regular dictionary, but it logs all read access to a file. To get the basic behavior of a dictionary, we
need to be able to get, set and delete key/value pairs, check for key existence and count the number of
records in the dictionary. To get all of that behavior, we will need to implement the following methods:
125
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
Listing 6-22.
__getitem__(self, key)
__setitem__(self, key, value)
__delitem__(self, key)
__contains__(self, item)
__len__(self)
The method names are fairly self-explanatory. __gettiem__, __setitem__ and __delitem__ all
manipulate key/value pairs in our dictionary. We can implement this behavior on top of a regular list
object to get a naïve implementation. Put the following code into a file named “foo.py.”
Listing 6-23.
class SimpleDict(object):
def __init__(self):
self._items = []
def __getitem__(self, key):
# do a brute force key lookup and return the value
for k, v in self._items:
if k == key:
return v
raise LookupError, "can't find key: [%s]" % key
def __setitem__(self, key, value):
# do a brute force search and replace
# for the key if it exists. Otherwise append
# a new key/value pair.
for i, (k , v) in enumerate(self._items):
if k == key:
self._items[i][1] = v
return
self._items.append((key, value))
def __delitem__(self, key):
# do a brute force search and delete
for i, (k , v) in enumerate(self._items):
if k == key:
del self._items[i]
return
raise LookupError, "Can't find [%s] to delete" % key
The implementations listed previously are naïve, but they should illustrate the basic pattern of
usage. Once you have just those three methods implemented, you can start using dictionary style
attribute access.
Listing 6-24.
>>> from foo import *
>>> x = SimpleDict()
>>> x[0] = 5
126
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
>>> x[15]= 32
>>> print x[0]
5
>>> print x[15]
32
To get two remaining behaviors, key existence and dictionary size, we fill in the __contains__ and
__len__ methods.
Listing 6-25.
def __contains__(self, key):
return key in [k for (k, v) in self._items]
def __len__(self):
return len(self._items)
Now this implementation of a dictionary will behave almost identically to a standard dictionary,
we’re still missing some “regular” methods like items(), keys() and values(), but accessing the SimpleDict
using square brackets will work the way you expect a dictionary to work. While this implementation was
intentionally made to be simple, it is easy to see that we could have saved our items into a text file, a
database backend or any other backing storage. The caller would be blind to these changes; all they
would interact with is the dictionary interface.
Default Arguments
One particular snag that seems to catch every Jython programmer is when you use default values in a
method signature.
Listing 6-26.
>>>
...
...
...
...
>>>
>>>
[1]
>>>
[1,
>>>
[1,
class Tricky(object):
def mutate(self, x=[]):
x.append(1)
return x
obj = Tricky()
obj.mutate()
obj.mutate()
1]
obj.mutate()
1, 1]
What’s happening here is that the instance method “mutate” is an object. The method object stores
the default value for “x” in an attribute inside the method object. To complicate things further, method
objects are bound to your class definition. So when you go and mutate the list, you’re actually changing
the value of an attribute of the method itself. Each of your object instances point to the same class
definition, and the same method. Your default arguments will change for all of your instances!
127
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
Runtime Binding of Methods
One interesting feature of Jython is that instance methods are actually just attributes hanging off of the
class definition; the functions are just attributes like any other variable, except that they happen to be
“callable.”
It’s even possible to create and bind in functions to a class definition at runtime using the new
module to create instance methods. In the following example, you can see that it’s possible to define a
class with nothing in it, and then bind methods to the class definition at runtime.
Listing 6-27.
>>> def some_func(self, x, y):
...
print "I'm in object: %s" % self
...
return x * y
...
>>> import new
>>> class Foo(object): pass
...
>>> f = Foo()
>>> f
<__main__.Foo object at 0x1>
>>> Foo.mymethod = new.instancemethod(some_func, f, Foo)
>>> f.mymethod(6,3)
I'm in object: <__main__.Foo object at 0x1>
18
When you invoke the mymethod method, the same attribute lookup machinery is being invoked.
Jython looks up the name against the “self” object. When it can’t find anything there, it goes to the class
definition. When it finds it there, the instancemethod object is returned. The function is then called with
two arguments and you get to see the final result.
The special function new.instancemethod is doing some magic so that when some_func is invoked,
the Jython runtime will automatically pass in the object instance as the first argument. That’s the self
attribute we saw earlier in this chapter. Functions that are bound to an object in this manner are
appropriately called “bound methods.” Without this binding behavior, the object instance will not be
passed in as the first argument. In this case, the method would be called an “unbound method.”
This kind of dynamism in Jython is extremely powerful. You can write code that generates functions
at program runtime, and then bind those functions to objects. You can do all of this because in Jython,
classes and functions are what are known as “first-class objects.” The class definition itself is an actual
object, just like any other object. Manipulating classes is as easy as manipulating any other object.
The practical use of this kind of technique is when you are building tools that generate code. Instead
of statically code generating functions and methods, you can “grow” your methods depending on
runtime features of your objects. This is how most of the Python database toolkits work. You define
classes that represent objects in your database, and the toolkit will inspect your objects and enhance the
classes with persistence behavior. Using dynamic programming techniques, like creating new methods
at runtime, opens up the possibility of literally post-processing your classes.
Caching Attribute Access
Suppose we have some method that requires intensive computational resources to run, but the results
do not vary much over time. Wouldn’t it be nice if we could cache the results so that the computation
wouldn’t have to run each and every time? We can leverage the decorator pattern in Chapter 4 and add
write the results of our computations as new attributes of our objects.
128
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
Here’s our class with a slow computation method. The slow_compute() method really doesn’t do
anything interesting; it just sleeps and eats up one second of time. We’re going to wrap the method up
with a caching decorator so that we don’t have to wait the one second every time we invoke the method.
Listing 6-28.
import time
class Foobar(object):
def slow_compute(self, *args, **kwargs):
time.sleep(1)
return args, kwargs, 42
Now let’s cache the value using a decorator function. Our strategy is that for any function named X
with some argument list, we want to create a unique name and save the final computed value to that
name. We want our cached value to have a human readable name, we want to reuse the original
function name, as well as the arguments that were passed in the first time.
Let’s get to some code!
Listing 6-29.
import hashlib
def cache(func):
"""
This decorator will add a _cache_functionName_HEXDIGEST
attribute after the first invocation of an instance method to
store cached values.
"""
# Obtain the function's name
func_name = func.func_name
# Compute a unique value for the unnamed and named arguments
arghash = hashlib.sha1(str(args) + str(kwargs)).hexdigest()
cache_name = '_cache_%s_%s' % (func_name, arghash)
def inner(self, *args, **kwargs):
if hasattr(self, cache_name):
# If we have a cached value, just use it
print "Fetching cached value from : %s" % cache_name
return getattr(self, cache_name)
result = func(self, *args, **kwargs)
setattr(self, cache_name, result)
return result
return inner
There are only two new tricks that are in this code.
1.
We’re using the hashlib module to convert the arguments to the function into
a unique single string.
2.
We’re using getattr, hasattr, and setattr to manipulate the cached value on the
instance object.
The three functions getattr, setattr, and hasattr allow you to get, set, and test for attributes on an
object by using string names instead of symbols. So accessing foo.bar is equivalent to invoking
129
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
getattr(foo, ‘bar’). In the previous case, we’re using the attribute functions to bind the result of the slow
calculation function into an attribute of an instance of Foobar.
The next time the decorated method is invoked, the hasattr test will find the cached value and we
return the precomputed value.
Now, if we want to cache the slow method, we just throw on a @cache line above the method
declaration.
Listing 6-30.
@cache
def slow_compute(self, *args, **kwargs):
time.sleep(1)
return args, kwargs, 42
Fantastic! We can reuse this cache decorator for any method we want now. Let’s suppose now that
we want our cache to invalidate itself after every N number of calls. This practical use of currying is only
a slight modification to the original caching code. The goal is the same; we are going to store the
computed result of a method as an attribute of an object. The name of the attribute is determined based
on the actual function name, and is concatenated with a hash string computed by using the arguments
to the method.
In the code sample, we’ll save the function name into the variable “func_name” and we’ll save the
argument hash value into “arghash.”
Those two variables will also be used to compute the name of a counter attribute. When the counter
reaches N, we’ll clear out the precomputed value so that the calculation can run again.
Listing 6-31.
import hashlib
def cache(loop_iter):
def function_closure(func):
func_name = func.func_name
def closure(self, loop_iter, *args, **kwargs):
arghash = hashlib.sha1(str(args) + str(kwargs)).hexdigest()
cache_name = '_cache_%s_%s' % (func_name, arghash)
counter_name = '_counter_%s_%s' % (func_name, arghash)
if hasattr(self, cache_name):
# If we have a cached value, just use it
print "Fetching cached value from : %s" % cache_name
loop_iter -= 1
setattr(self, counter_name, loop_iter)
result = getattr(self, cache_name)
if loop_iter == 0:
delattr(self, counter_name)
delattr(self, cache_name)
print "Cleared cached value"
return result
result = func(self, *args, **kwargs)
setattr(self, cache_name, result)
130
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
setattr(self, counter_name, loop_iter)
return result
return closure
return function_closure
Now we’re free to use @cache for any slow method and caching will come in for free, including
automatic invalidation of the cached value. Just use it like this:
Listing 6-32.
@cache(10)
def slow_compute(self, *args, **kwargs):
# TODO: stuff goes here...
pass
Summary
Now, we’re going to ask you to use your imagination a little. We’ve covered quite a bit of ground really
quickly.
We can:
•
look up attributes in an object (use the __dict__ attribute);
•
check if an object belongs to a particular class hierarchy (use the isinstance
function);
•
build functions out of other functions using currying and even bind those
functions to arbitrary names.
This is fantastic. We now have all the basic building blocks we need to generate complex methods
based on the attributes of our class. Imagine a simplified addressbook application with a simple contact.
Listing 6-33.
class Contact(object):
first_name = str
last_name = str
date_of_birth = datetime.Date
Assuming we know how to save and load to a database, we can use the function generation
techniques to automatically generate load() and save() methods and bind them into our Contact class.
We can use our introspection techniques to determine what attributes need to be saved to our database.
We could even grow special methods onto our Contact class so that we could iterate over all of the class
attributes and magically grow ‘searchby_first_name’ and ‘searchby_last_name’ methods.
Jython’s flexible object system allows you to write code that has a deep ability to introspect itself by
simply looking up information in dictionaries like __dict__. You also have the ability to rewrite parts of
your classes using decorators and even creating new instance methods at runtime. These techniques can
be combined together to write code that effectively rewrites itself. This technique is called
‘metaprogramming’. This technique is very powerful: we can write extremely minimal code, and we can
code generate all of our specialized behavior. In the case of our contact, it would “magically” know how
131
www.it-ebooks.info
CHAPTER 6 ■ OBJECT-ORIENTED JYTHON
to save itself, load itself, and delete itself from a database. This is precisely how the database mappers in
Django and SQLAlchemy work: they rewrite parts of your program to talk to a database. We urge you to
open up the source code to those libraries to see how you can apply some of these techniques in real
world settings.
132
www.it-ebooks.info
CHAPTER 7
■■■
Exception Handling and Debugging
Any good program makes use of a language’s exception handling mechanisms. There is no better way to
frustrate an end-user then by having them run into an issue with your software and displaying a big ugly
error message on the screen, followed by a program crash. Exception handling is all about ensuring that
when your program encounters an issue, it will continue to run and provide informative feedback to the
end-user or program administrator. Any Java programmer becomes familiar with exception handling on
day one, as some Java code won’t even compile unless there is some form of exception handling put into
place via the try-catch-finally syntax. Python has similar constructs to that of Java, and we’ll discuss
them in this chapter.
After you have found an exception, or preferably before your software is distributed, you should go
through the code and debug it in order to find and repair the erroneous code. There are many different
ways to debug and repair code; we will go through some debugging methodologies in this chapter. In
Python as well as Java, the assert keyword can help out tremendously in this area. We’ll cover assert in
depth here and learn the different ways that it can be used to help you out and save time debugging
those hard-to-find errors.
Exception Handling Syntax and Differences with Java
Java developers are very familiar with the try-catch-finally block as this is the main mechanism that is
used to perform exception handling. Python exception handling differs a bit from Java, but the syntax is
fairly similar. However, Java differs a bit in the way that an exception is thrown in code. Now, realize that
I just used the term throw…this is Java terminology. Python does not throw exceptions, but instead it
raises them. Two different terms which mean basically the same thing. In this section, we’ll step through
the process of handling and raising exceptions in Python code, and show you how it differs from that in
Java.
For those who are unfamiliar, I will show you how to perform some exception handling in the Java
language. This will give you an opportunity to compare the two syntaxes and appreciate the flexibility
that Python offers.
Listing 7-1. Exception Handling in Java
try {
// perform some tasks that may throw an exception
} catch (ExceptionType messageVariable) {
// perform some exception handling
} finally {
// execute code that must always be invoked
}
133
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
Now let’s go on to learn how to make this work in Python. Not only will we see how to handle and
raise exceptions, but you’ll also learn some other great techniques such as using assertions later in the
chapter.
Catching Exceptions
How often have you been working in a program and performed some action that caused the program to
abort and display a nasty error message? It happens more often than it should because most exceptions
can be caught and handled nicely. By nicely, I mean that the program will not abort and the end user will
receive a descriptive error message stating what the problem is, and in some cases how it can be
resolved. The exception handling mechanisms within programming languages were developed for this
purpose.
Listing 7-2. try-except Example
# This function uses a try-except clause to provide a nice error
# message if the user passes a zero in as the divisor
>>> from __future__ import division
>>> def divide_numbers(x, y):
...
try:
...
return x/y
...
except ZeroDivisionError:
...
return 'You cannot divide by zero, try again'
…
# Attempt to divide 8 by 3
>>> divide_numbers(8,3)
2.6666666666666665
# Attempt to divide 8 by zero
>>> divide_numbers(8, 0)
'You cannot divide by zero, try again'
Table 7-1 lists of all exceptions that are built into the Python language along with a description of
each. You can write any of these into an except clause and try to handle them. Later in this chapter I will
show you how you and raise them if you’d like. Lastly, if there is a specific type of exception that you’d
like to throw that does not fit any of these, then you can write your own exception type object. It is
important to note that Python exception handling differs a bit from Java exception handling. In Java,
many times the compiler forces you to catch exceptions, such is known as checked exceptions. Checked
exceptions are basically exceptions that a method may throw while performing some task. The developer
is forced to handle these checked exceptions using a try/catch or a throws clause, otherwise the compiler
complains. Python has no such facility built into its error handling system. The developer decides when
to handle exceptions and when not to do so. It is a best practice to include error handling wherever
possible even though the interpreter does not force it.
Exceptions in Python are special classes that are built into the language. As such, there is a class
hierarchy for exceptions and some exceptions are actually subclasses of another exception class. In this
case, a program can handle the superclass of such an exception and all subclassed exceptions are
handled automatically. Table 7-1 lists the exceptions defined in the Python language, and the
indentation resembles the class hierarchy.
134
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
Table 7-1. Exceptions
Exception
Description
BaseException
GeneratorExit
KeyboardInterrupt
SystemExit
Exception
StopIteration
StandardError
ArithmeticError
FloatingPointError
OverflowError
ZeroDivisionError
AssertionError
AttributeError
EnvironmentError
IOError
OSError
EOFError
ImportError
LookupError
IndexError
KeyError
MemoryError
NameError
UnboundLocalError
ReferenceError
RuntimeError
NotImplementedError
SyntaxError
IndentationError
TabError
SystemError
TypeError
ValueError
Warning
This is the root exception for all others
Raised by close() method of generators for terminating iteration
Raised by the interrupt key
Program exit
Root for all non-exiting exceptions
Raised to stop an iteration action
Base class for all built-in exceptions
Base for all arithmetic exceptions
Raised when a floating-point operation fails
Arithmetic operations that are too large
Division or modulo operation with zero as divisor
Raised when an assert statement fails
Attribute reference or assignment failure
An error occurred outside of Python
Error in Input/Output operation
An error occurred in the os module
input() or raw_input() tried to read past the end of a file
Import failed to find module or name
Base class for IndexError and KeyError
A sequence index goes out of range
Referenced a non-existent mapping (dict) key
Memory exhausted
Failure to find a local or global name
Unassigned local variable is referenced
Attempt to access a garbage-collected object
Obsolete catch-all error
Raised when a feature is not implemented
Parser encountered a syntax error
Parser encountered an indentation issue
Incorrect mixture of tabs and spaces
Non-fatal interpreter error
Inappropriate type was passed to an operator or function
Argument error not covered by TypeError or a more precise error
Base for all warnings
135
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
The try-except-finally block is used in Python programs to perform the exception-handling task. Much
like that of Java, code that may or may not raise an exception can be placed in the try block. Differently
though, exceptions that may be caught go into an except block much like the Java catch equivalent. Any
tasks that must be performed no matter if an exception is thrown or not should go into the finally block.
All tasks within the finally block are performed if an exception is raised either within the except block or
by some other exception. The tasks are also performed before the exception is raised to ensure that they
are completed. The finally block is a great place to perform cleanup activity such as closing open files
and such.
Listing 7-3. try-except-finally Logic
try:
# perform some task that may raise an exception
except Exception, value:
# perform some exception handling
finally:
# perform tasks that must always be completed (Will be performed before the exception is
# raised.)
Python also offers an optional else clause to create the try-except-else logic. This optional code
placed inside the else block is run if there are no exceptions found in the block.
Listing 7-4. try-finally logic
try:
# perform some tasks that may raise an exception
finally:
# perform tasks that must always be completed (Will be performed before the exception is
# raised.)
The else clause can be used with the exception handling logic to ensure that some tasks are only run
if no exceptions are raised. Code within the else clause is only initiated if no exceptions are thrown, and if
any exceptions are raised within the else clause the control does not go back out to the except. Such
activities to place in inside an else clause would be transactions such as a database commit. If several
database transactions were taking place inside the try clause you may not want a commit to occur unless
there were no exceptions raised.
Listing 7-5. try-except-else logic:
try:
# perform some tasks that may raise an exception
except:
# perform some exception handling
else:
# perform some tasks thatwill only be performed if no exceptions are thrown
You can name the specific type of exception to catch within the except block, or you can generically
define an exception handling block by not naming any exception at all. Best practice of course states that
you should always try to name the exception and then provide the best possible handling solution for
the case. After all, if the program is simply going to spit out a nasty error then the exception handling
block is not very user friendly and is only helpful to developers. However, there are some rare cases
where it would be advantageous to not explicitly refer to an exception type when we simply wish to
136
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
ignore errors and move on. The except block also allows us to define a variable to which the exception
message will be assigned. This allows us the ability to store that message and display it somewhere
within our exception handling code block. If you are calling a piece of Java code from within Jython and
the Java code throws an exception, it can be handled within Jython in the same manner as Jython
exceptions.
Listing 7-6. Exception Handling in Python
# Code without an exception handler
>>> x = 10
>>> z = x / y
Traceback (most recent call last):
File "", line 1, in
NameError: name 'y' is not defined
# The same code with an exception handling block
>>> x = 10
>>> try:
...
z = x / y
... except NameError, err:
...
print "One of the variables was undefined: ", err
...
One of the variables was undefined: name 'y' is not defined
It is important to note that Jython 2.5.x uses the Python 2.5.x exception handling syntax. This syntax
will be changing in future releases of Jython. Take note of the syntax that is being used for defining the
variable that holds the exception. Namely, the except ExceptionType, value statement syntax in Python
and Jython 2.5 differs from that beyond 2.5. In Python 2.6, the syntax changes a bit in order to ready
developers for Python 3, which exclusively uses the new syntax.
Listing 7-7. Jython and Python 2.5 and Prior
try:
# code
except ExceptionType, messageVar:
# code
Listing 7-8. Jython 2.6 (Not Yet Implemented) and Python 2.6 and Beyond
try:
# code
except ExceptionType as messageVar:
# code
We had previously mentioned that it was simply bad programming practice to not explicitly name
an exception type when writing exception handling code. This is true, however Python provides us with
another a couple of means to obtain the type of exception that was thrown. The easiest way to find an
exception type is to simply catch the exception as a variable as we’ve discussed previously. You can then
find the specific exception type by using the type(error_variable) syntax if needed.
137
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
Listing 7-9. Determining Exception Type
# In this example, we catch a general exception and then determine the type later
>>> try:
...
8/0
... except Exception, ex1:
...
'An error has occurred'
...
'An error has occurred'
>>> ex1
ZeroDivisionError('integer division or modulo by zero',)
>>> type(ex1)
>>>
There is also a function provided in the sys package known as sys.exc_info() that will provide us with
both the exception type and the exception message. This can be quite useful if we are wrapping some
code in a try-except block but we really aren’t sure what type of exception may be thrown. Below is an
example of using this technique.
Listing 7-10. Using sys.exc_info()
# Perform exception handling without explicitly naming the exception type
>>> x = 10
>>> try:
...
z = x / y
... except:
...
print "Unexpected error: ", sys.exc_info()[0], sys.exc_info()[1]
...
Unexpected error: name 'y' is not defined
Sometimes you may run into a situation where it is applicable to catch more than one exception.
Python offers a couple of different options if you need to do such exception handling. You can either use
multiple except clauses, which does the trick and works well if you’re interested in performing different
tasks for each different exception that occurs, but may become too wordy. The other preferred option is
to enclose your exception types within parentheses and separated by commas on your except statement.
Take a look at the following example that portrays the latter approach using Listing 7-6.
Listing 7-11. Handling Multiple Exceptions
# Catch NameError, but also a ZeroDivisionError in case a zero is used in the equation
>>> try:
...
z = x/y
... except(NameError, ZeroDivisionError), err:
...
"An error has occurred, please check your values and try again"
...
'An error has occurred, please check your values and try again'
138
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
# Using multiple except clauses
>>> x = 10
>>> y = 0
>>> try:
...
z = x / y
... except NameError, err1:
...
print err1
... except ZeroDivisionError, err2:
...
print 'You cannot divide a number by zero!'
...
You cannot divide a number by zero!
As mentioned previously, an exception is simply a class in Python. There are superclasses and
subclasses for exceptions. You can catch a superclass exception to catch any of the exceptions that
subclass that exception are thrown. For instance, if a program had a specific function that accepted
either a list or dict object, it would make sense to catch a LookupError as opposed to finding a KeyError
or IndexError separately. Look at the following example to see one way that this can be done.
Listing 7-12. Catching a Superclass Exceptions
#
#
#
#
In the following example, we define a function that will return
a value from some container. The function accepts either lists
or dictionary objects. The LookupError superclass is caught
as opposed to checking for each of it's subclasses...namely KeyError and IndexError.
>>> def find_value(obj, value):
...
try:
...
return obj[value]
...
except LookupError, ex:
...
return 'An exception has been raised, check your values and try again'
...
# Create both a dict and a list and test the function by looking for a value that does
# not exist in either container
>>>
>>>
>>>
'An
>>>
3
>>>
'An
>>>
mydict = {'test1':1,'test2':2}
mylist = [1,2,3]
find_value(mydict, 'test3')
exception has been raised, check your values and try again'
find_value(mylist, 2)
find_value(mylist, 3)
exception has been raised, check your values and try again'
If multiple exception blocks have been coded, the first matching exception is the one that is caught.
For instance, if we were to redesign the find_value function that was defined in the previous example,
but instead raised each exception separately then the first matching exception would be raised. . .the
others would be ignored. Let’s see how this would work.
139
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
Listing 7-13. Catching the First Matching Exceptions
# Redefine the find_value() function to check for each exception separately
# Only the first matching exception will be raised, others will be ignored.
# So in these examples, the except LookupError code is never run.
>>> def find_value(obj, value):
...
try:
...
return obj[value]
...
except KeyError:
...
return 'The specified key was not in the dict, please try again'
...
except IndexError:
...
return 'The specified index was out of range, please try again'
...
except LookupError:
...
return 'The specified key was not found, please try again'
...
>>> find_value(mydict, 'test3')
'The specified key was not in the dict, please try again'
>>> find_value(mylist, 3)
'The specified index was out of range, please try again'
>>>
'
The try-except block can be nested as deep as you’d like. In the case of nested exception handling
blocks, if an exception is thrown then the program control will jump out of the inner most block that
received the error, and up to the block just above it. This is very much the same type of action that is
taken when you are working in a nested loop and then run into a break statement, your code will stop
executing and jump back up to the outer loop. The following example shows an example for such logic.
Listing 7-14. Nested Exception Handling Blocks
# Perform some division on numbers entered by keyboard
try:
# do some work
try:
x = raw_input ('Enter a number for the dividend:
y = raw_input('Enter a number to divisor: ')
x = int(x)
y = int(y)
except ValueError:
# handle exception and move to outer try-except
print 'You must enter a numeric value!'
z = x / y
except ZeroDivisionError:
# handle exception
print 'You cannot divide by zero!'
except TypeError:
print 'Retry and only use numeric values this time!'
else:
print 'Your quotient is: %d' % (z)
140
www.it-ebooks.info
')
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
In the previous example, we nested the different exception blocks. If the first ValueError were raised,
it would give control back to the outer exception block. Therefore, the ZeroDivisionError and TypeError
could still be raised. Otherwise, if those last two exceptions are not thrown then the tasks within the else
clause would be run.
As stated previously, it is a common practice in Jython to handle Java exceptions. Oftentimes we
have a Java class that throws exceptions, and these can be handled or displayed in Jython just the same
way as handling Python exceptions.
Listing 7-15. Handling Java Exceptions in Jython
// Java Class TaxCalc
public class TaxCalc {
public static void main(String[] args) {
double cost = 0.0;
int pct
= 0;
double tip = 0.0;
try {
cost = Double.parseDouble(args[0]);
pct = Integer.parseInt(args[1]);
tip = (cost * (pct * .01));
System.out.println("The total gratutity based on " + pct + " percent would be "
+
tip);
System.out.println("The total bill would be " + (cost + tip) );
} catch (NumberFormatException ex){
System.out.println("You must pass number values as arguments. Exception: " +
ex);
} catch (ArrayIndexOutOfBoundsException ex1){
System.out.println("You must pass two values to this utility.
TaxCalc(cost, percentage) Exception: " + ex1);
}
}
}
Format:
Using Jython:
# Now lets bring the TaxCalc Java class into Jython and use it
>>> import TaxCalc
>>> calc = TaxCalc()
# pass strings within a list to the TaxCalc utility and the Java exception will be thrown
>>> vals = ['test1','test2']
>>> calc.main(vals)
You must pass number values as arguments. Exception: java.lang.NumberFormatException: For
input string: "test1"
# Now pass numeric values as strings in a list, this works as expected (except for the bad
# rounding)
>>> vals = ['25.25', '20']
>>> calc.main(vals)
The total gratutity based on 20 percent would be 5.050000000000001
The total bill would be 30.3
141
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
You can also throw Java exceptions in Jython by simply importing them first and then using then
raising them just like Python exceptions.
Raising Exceptions
Often you will find reason to raise your own exceptions. Maybe you are expecting a certain type of
keyboard entry, and a user enters something incorrectly that your program does not like. This would be
a case when you’d like to raise your own exception. The raise statement can be used to allow you to raise
an exception where you deem appropriate. Using the raise statement, you can cause any of the Python
exception types to be raised, you could raise your own exception that you define (discussed in the next
section). The raise statement is analogous to the throw statement in the Java language. In Java we may
opt to throw an exception if necessary. However, Java also allows you to apply a throws clause to a
particular method if an exception may possibly be thrown within instead of using try-catch handler in
the method. Python does not allow you do perform such techniques using the raise statement.
Listing 7-16. raise Statement Syntax
raise ExceptionType or String[, message[, traceback]]
As you can see from the syntax, using raise allows you to become creative in that you could use your
own string when raising an error. However, this is not really looked upon as a best practice as you should
try to raise a defined exception type if at all possible. You can also provide a short message explaining
the error. This message can be any string. Let’s take a look at an example.
Listing 7-17. raising Exceptions Using Message
>>> raise Exception("An exception is being raised")
Traceback (most recent call last):
File "", line 1, in
Exception: An exception is being raised
>>> raise TypeError("You've specified an incorrect type")
Traceback (most recent call last):
File "", line 1, in
TypeError: You've specified an incorrect type
Now you’ve surely seen some exceptions raised in the Python interpreter by now. Each time an
exception is raised, a message appears that was created by the interpreter to give you feedback about the
exception and where the offending line of code may be. There is always a traceback section when any
exception is raised. This really gives you more information on where the exception was raised. Lastly,
let’s take a look at raising an exception using a different format. Namely, we can use the format raise
Exception, “message”.
Listing 7-18. Using the raise Statement with the Exception, “message” Syntax
>>> raise TypeError,"This is a special message"
Traceback (most recent call last):
File "", line 1, in
TypeError: This is a special message
142
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
Defining Your Own Exceptions
You can define your own exceptions in Python by creating an exception class. You simply define a class
that inherits from the base Exception class. The easiest defined exception can simply use a pass
statement inside the class. Exception classes can accept parameters using the initializer, and return the
exception using the __str__ method. Any exception you write should accept a message. It is also a good
practice to name your exception giving it a suffix of Error if the exception is referring to an error of some
kind.
Listing 7-19. Defining a Basic Exception Class
class MyNewError(Exception):
pass
This example is the simplest type of exception you can create. This exception that was created above
can be raised just like any other exception now.
raise MyNewError("Something happened in my program")
A more involved exception class may be written as follows.
Listing 7-20. Exception Class Using Initializer
class MegaError(Exception):
""" This is raised when there is a huge problem with my program"""
def __init__(self, val):
self.val = val
def __str__(self):
return repr(self.val)
Issuing Warnings
Warnings can be raised at any time in your program and can be used to display some type of warning
message, but they do not necessarily cause execution to abort. A good example is when you wish to
deprecate a method or implementation but still make it usable for compatibility. You could create a
warning to alert the user and let them know that such methods are deprecated and point them to the
new definition, but the program would not abort. Warnings are easy to define, but they can be complex
if you wish to define rules on them using filters. Warning filters are used to modify the behavior of a
particular warning. Much like exceptions, there are a number of defined warnings that can be used for
categorizing. In order to allow these warnings to be easily converted into exceptions, they are all
instances of the Exception type. Remember that exceptions are not necessarily errors, but rather alerts or
messages. For instance, the StopIteration exception is raised by a program to stop the iteration of a
loop…not to flag an error with the program.
To issue a warning, you must first import the warnings module into your program. Once this has
been done then it is as simple as making a call to the warnings.warn() function and passing it a string
with the warning message. However, if you’d like to control the type of warning that is issued, you can
also pass the warning class. Warnings are listed in Table 7-2.
143
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
Listing 7-21. Issuing a Warning
# Always import the warnings module first
import warnings
# A couple of examples for setting up warnings
warnings.warn("this feature will be deprecated")
warnings.warn("this is a more involved warning", RuntimeWarning)
# Using A Warning in a Function
# Suppose that use of the following function has been deprecated,
# warnings can be used to alert the function users
# The following function calculates what the year will be if we
# add the specified number of days to the current year. Of course,
# this is pre-Y2K code so it is being deprecated. We certainly do not
# want this code around when we get to year 3000!
>>> def add_days(current_year, days):
...
warnings.warn("This function has been deprecated as of version x.x",
DeprecationWarning)
...
num_years = 0
...
if days > 365:
...
num_years = days/365
...
return current_year + num_years
...
# Calling the function will return the warning that has been set up,
# but it does not raise an error...the expected result is still returned.
>>> add_days(2009, 450)
__main__:2: DeprecationWarning: This function has been deprecated as of version x.x
2010
Table 7-2. Python Warning Categories
Warning
Description
Warning
Root warning class
UserWarning
A user-defined warning
DeprecationWarning
Warns about use of a deprecated feature
SyntaxWarning
Syntax issues
RuntimeWarning
Runtime issues
FutureWarning
Warns that a particular feature will be changing in a future release
144
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
Importing the warnings module into your code gives you access to a number of built-in warning
functions that can be used. If you’d like to filter a warning and change its behavior then you can do so by
creating a filter. Table 7-3 lists functions that come with the warnings module.
Table 7-3. Warning Functions
Function
Description
warn(message[, category[,
stacklevel]])
Issues a warning. Parameters include a message string, the optional
category of warning, and the optional stack level that tells which
stack frame the warning should originate from, usually either the
calling function or the source of the function itself.
warn_explicit(message,
category, filename, lineno[,
module[, registry]])
This offers a more detailed warning message and makes category a
mandatory parameter. filename, lineno, and module tell where the
warning is located. registry represents all of the current warning
filters that are active.
showwarning(message,
category, filename, lineno[,
file])
Gives you the ability to write the warning to a file.
formatwarning(message,
category, filename, lineno)
Creates a formatted string representing the warning.
simplefilter(action[, category[,
lineno[, append]]])
Inserts simple entry into the ordered list of warnings filters. Regular
expressions are not needed for simplefilter as the filter always
matches any message in any module as long as the category and line
number match. filterwarnings() described below uses a regular
expression to match against warnings.
resetwarnings()
Resets all of the warning filters.
filterwarnings(action[,
message[, category[, module[,
lineno[, append]]]]])
This adds an entry into a warning filter list. Warning filters allow you
to modify the behavior of a warning. The action in the warning filter
can be one from those listed in Table 7-4, message is a regular
expression, category is the type of a warning to be issued, module
can be a regular expression, lineno is a line number to match against
all lines, append specifies whether the filter should be appended to
the list of all filters.
145
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
Table 7-4. Python Filter Actions
Filter Actions
‘always’
Always print warning message
‘default’
Print warning once for each location where warning occurs
‘error’
Converts a warning into an exception
‘ignore’
Ignores the warning
‘module’
Print warning once for each module in which warning occurs
‘once’
Print warning only one time
Let’s take a look at a few ways to use warning filters in the examples below.
Listing 7-22. Warning Filter Examples
# Set up a simple warnings filter to raise a warning as an exception
>>> warnings.simplefilter('error', UserWarning)
>>> warnings.warn('This will be raised as an exception')
Traceback (most recent call last):
File "", line 1, in
File "/Applications/Jython/jython2.5.1rc2/Lib/warnings.py", line 63, in warn
warn_explicit(message, category, filename, lineno, module, registry,
File "/Applications/Jython/jython2.5.1rc2/Lib/warnings.py", line 104, in warn_explicit
raise message
UserWarning: This will be raised as an exception
# Turn off all active filters using resetwarnings()
>>> warnings.resetwarnings()
>>> warnings.warn('This will not be raised as an exception')
__main__:1: UserWarning: This will not be raised as an exception
# Use a regular expression to filter warnings
# In this case, we ignore all warnings containing the word “one”
>>> warnings.filterwarnings('ignore', '.*one*.',)
>>> warnings.warn('This is warning number zero')
__main__:1: UserWarning: This is warning number zero
>>> warnings.warn('This is warning number one')
>>> warnings.warn('This is warning number two')
__main__:1: UserWarning: This is warning number two
>>>
There can be many different warning filters in use, and each call to the filterwarnings() function will
append another warning to the ordered list of filters if so desired. The specific warning is matched
against each filter specification in the list in turn until a match is found. In order to see which filters are
146
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
currently in use, issue the command print warnings.filters. One can also specify a warning filter from the
command line by use of the –W option. Lastly, all warnings can be reset to defaults by using the
resetwarnings() function.
It is also possible to set up a warnings filter using a command-line argument. This can be quite
useful for filtering warnings on a per-script or per-module basis. For instance, if you are interested in
filtering warnings on a per-script basis then you could issue the -W command line argument while
invoking the script.
Listing 7-23. -W command-line option
-Waction:message:category:module:lineno
Listing 7-24. Example of using W command line option
# Assume we have the following script test_warnings.py
# and we are interested in running it from the command line
import warnings
def test_warnings():
print "The function has started"
warnings.warn("This function has been deprecated", DeprecationWarning)
print "The function has been completed"
if __name__ == "__main__":
test_warnings()
# Use the following syntax to start and run jython as usual without
# filtering any warnings
jython test_warnings.py
The function has started
test_warnings.py:4: DeprecationWarning: This function has been deprecated
warnings.warn("This function has been deprecated", DeprecationWarning)
The function has been completed
# Run the script and ignore all deprecation warnings
jython -W "ignore::DeprecationWarning::0" test_warnings.py
The function has started
The function has been completed
# Run the script one last time and treat the DeprecationWarning
# as an exception. As you see, it never completes
jython -W "error::DeprecationWarning::0" test_warnings.py
The function has started
Traceback (most recent call last):
File "test_warnings.py", line 8, in
test_warnings()
File "test_warnings.py", line 4, in test_warnings
warnings.warn("This function has been deprecated", DeprecationWarning)
File "/Applications/Jython/jython2.5.1rc2/Lib/warnings.py", line 63, in warn
warn_explicit(message, category, filename, lineno, module, registry,
File "/Applications/Jython/jython2.5.1rc2/Lib/warnings.py", line 104, in warn_explicit
raise message
DeprecationWarning: This function has been deprecated
147
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
Warnings can be very useful in some situations. They can be made as simplistic or sophisticated as
need be.
Assertions and Debugging
Debugging can be an easy task in Python via use of the assert statement. In CPython, the __debug__
variable can also be used, but this feature is currently not usable in Jython as there is no optimization
mode for the interpreter. . Assertions are statements that can print to indicate that a particular piece of
code is not behaving as expected. The assertion checks an expression for a True or False value, and if it
evaluates to False in a Boolean context then it issues an AssertionError along with an optional message. If
the expression evaluates to True then the assertion is ignored completely.
assert expression [, message]
By effectively using the assert statement throughout your program, you can easily catch any errors
that may occur and make debugging life much easier. Listing 7-25 will show you the use of the assert
statement.
Listing 7-25. Using assert
# The following example shows how assertions are evaluated
>>> x = 5
>>> y = 10
>>> assert x < y, "The assertion is ignored"
>>> assert x > y, "The assertion raises an exception"
Traceback (most recent call last):
File "", line 1, in
AssertionError: The assertion raises an exception
# Use assertions to validate parameters# Here we check the type of each parameter to ensure
# that they are integers
>>> def add_numbers(x, y):
...
assert type(x) is int, "The arguments must be integers, please check the first
argument"
...
assert type(y) is int, "The arguments must be integers, please check the second
argument"
...
return x + y
...
# When using the function, AssertionErrors are raised as necessary
>>> add_numbers(3, 4)
7
>>> add_numbers('hello','goodbye')
Traceback (most recent call last):
File "", line 1, in
File "", line 2, in add_numbers
AssertionError: The arguments must be integers, please check the first argument
Context Managers
Ensuring that code is written properly in order to manage resources such as files or database
connections is an important topic. If files or database connections are opened and never closed then our
program could incur issues. Often times, developers elect to make use of the try-finally blocks to ensure
148
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
that such resources are handled properly. While this is an acceptable method for resource management,
it can sometimes be misused and lead to problems when exceptions are raised in programs. For
instance, if we are working with a database connection and an exception occurs after we’ve opened the
connection, the program control may break out of the current block and skip all further processing. The
connection may never be closed in such a case. That is where the concept of context management
becomes an important new feature in Jython. Context management via the use of the with statement is
new to Jython 2.5, and it is a very nice way to ensure that resources are managed as expected.
In order to use the with statement, you must import from __future__. The with statement basically
allows you to take an object and use it without worrying about resource management. For instance, let’s
say that we’d like to open a file on the system and read some lines from it. To perform a file operation
you first need to open the file, perform any processing or reading of file content, and then close the file
to free the resource. Context management using the with statement allows you to simply open the file
and work with it in a concise syntax.
Listing 7-26. Python with Statement Example
# Read from a text file named players.txt
>>> from __future__ import with_statement
>>> with open('players.txt','r') as file:
...
x = file.read()
...
>>> print x
Sports Team Management
--------------------------------Josh – forward
Jim – defense
In this example, we did not worry about closing the file because the context took care of that for us.
This works with object that extends the context management protocol. In other words, any object that
implements two methods named __enter__() and __exit__() adhere to the context management protocol.
When the with statement begins, the __enter__() method is executed. Likewise, as the last action
performed when the with statement is ending, the __exit__() method is executed. The __enter__()
method takes no arguments, whereas the __exit__() method takes three optional arguments type, value,
and traceback. The __exit__() method returns a True or False value to indicate whether an exception was
thrown. The as variable clause on the with statement is optional as it will allow you to make use of the
object from within the code block. If you are working with resources such as a lock then you may not
need the optional clause.
If you follow the context management protocol, it is possible to create your own objects that can be
used with this technique. The __enter__() method should create whatever object you are trying to work if
needed.
149
www.it-ebooks.info
CHAPTER 7 ■ EXCEPTION HANDLING AND DEBUGGING
Listing 7-27. Creating a Simple Object That Follows Context Management Protocol
# In this example, my_object facilitates the context management protocol
# as it defines an __enter__ and __exit__ method
class my_object:
def __enter__(self):
# Perform setup tasks
return object
def __exit__(self, type, value, traceback):
# Perform cleanup
If you are working with an immutable object then you’ll need to create a copy of that object to work
with in the __enter__() method. The __exit__() method on the other hand can simply return False unless
there is some other type of cleanup processing that needs to take place. If an exception is raised
somewhere within the context manager, then __exit__() is called with three arguments representing
type, value, and traceback. However, if there are no exceptions raised then __exit__() is passed three
None arguments. If __exit__() returns True, then any exceptions are “swallowed” or ignored, and
execution continues at the next statement after the with-statement.
Summary
In this chapter, we discussed many different topics regarding exceptions and exception handling within
a Python application. First, you learned the exception handling syntax of the try-except-finally code
block and how it is used. We then discussed why it may be important to raise your own exceptions at
times and how to do so. That topic led to the discussion of how to define an exception and we learned
that in order to do so we must define a class that extends the Exception type object.
After learning about exceptions, we went into the warnings framework and discussed how to use it.
It may be important to use warnings in such cases where code may be deprecated and you want to warn
users, but you do not wish to raise any exceptions. That topic was followed by assertions and how
assertion statement can be used to help us debug our programs. Lastly, we touched upon the topic of
context managers and using the with statement that is new in Jython 2.5.
In the next chapter you will delve into the arena of building larger programs, learning about
modules and packages.
150
www.it-ebooks.info
CHAPTER 8
■■■
Modules and Packages for
Code Reuse
Up until this chapter, we have been looking at code at the level of the interactive console and simple
scripts. This works well for small examples, but when your program gets larger, it becomes necessary to
break programs up into smaller units. In Jython, the basic building block for these units in larger
programs is the module.
Imports for Reuse
Breaking code up into modules helps to organize large code bases. Modules can be used to logically
separate code that belongs together, making programs easier to understand. Modules are helpful for
creating libraries that can be imported and used in different applications that share some functionality.
Jython’s standard library comes with a large number of modules that can be used in your programs right
away.
Import Basics
The following is a very simple program that we can use to discuss imports.
breakfast.py
import search.scanner as scanner
import sys
class Spam(object):
def order(self, number):
print "spam " * number
def order_eggs():
print " and eggs!"
s = Spam()
s.order(3)
order_eggs()
We’ll start with a couple of definitions. A namespace is a logical grouping of unique identifiers. In
other words, a namespace is that set of names that can be accessed from a given bit of code in your
151
www.it-ebooks.info
CHAPTER 8 ■ MODULES AND PACKAGES FOR CODE REUSE
program. For example, if you open up a Jython prompt and type dir(), the names in the interpreter’s
namespace will be displayed.
>>> dir()
['__doc__', '__name__']
The interpreter namespace contains __doc__ and __name__. The __doc__ property contains the top
level docstring, which is empty in this case. We’ll get to the __name__ property in a moment. First we
need to talk about Jython modules. A module in Jython is a file containing Python definitions and
statements which in turn define a namespace. The module name is the same as the file name with the
suffix .py removed, so in our current example the Python file “breakfast.py” defines the module
“breakfast.”
Now we can talk about the __name__ property. When a module is run directly, as in jython
breakfast.py, __name__ will contain ‘__main__’. If a module is imported, __name__ will contain the
name of the module, so “import breakfast” results in the breakfast module containing a __name__ of
“breakfast”. Again from a basic Jython prompt:
>>> dir()
['__doc__', '__name__']
>>> __name__
'__main__'
Let’s see what happens when we import breakfast:
>>> import breakfast
spam spam spam
and eggs!
>>> dir()
['__doc__', '__name__', 'breakfast']
>>> import breakfast
>>>
Checking the dir() after the import shows that breakfast has been added to the top level namespace.
Notice that the act of importing actually executed the code in breakfast.py. This is the expected behavior
in Jython. When a module is imported, the statements in that module are actually executed. This
includes class and function definitions. It is important to note that this only happens the first time you
import a module. Note the last statement where we issue “import breakfast” again, resulting in no
output. Most of the time, we wouldn’t want a module to execute print statements when imported. To
avoid this, but allow the code to execute when it is called directly, we typically check the __name__
property. If the __name__ property is ‘__main__’, we know that the module was called directly instead of
being imported from another module.
class Spam(object):
def order(self, number):
print "spam " * number
def order_eggs():
print " and eggs!"
if __name__ == '__main__':
s = Spam()
s.order(3)
152
www.it-ebooks.info
CHAPTER 8 ■ MODULES AND PACKAGES FOR CODE REUSE
order_eggs()
Now if we import breakfast (remember to close and reopen the interpreter so that the module is
actually reimported!), we will not get the output:
>>> import breakfast
This is because in this case the __name__ property will contain ‘breakfast,’ the name of the module.
If we call breakfast.py from the commandline like “jython breakfast.py” we would then get the output
again, because breakfast would be executing as __main__:
$ jython breakfast.py
spam spam spam
and eggs!
The Import Statement
In Java, the Import statement is strictly a compiler directive that must occur at the top of the source file.
In Jython, the import statement is an expression that can occur anywhere in the source file, and can
even be conditionally executed.
As an example, a common idiom is to attempt to import something that may not be there in a try
block, and in the except block define the thing in some other way, or import it from a module that is
known to be there.
>>> try:
...
from blah import foo
...
print "imported normally"
... except ImportError:
...
print "defining foo in except block"
...
def foo():
...
return "hello from backup foo"
...
defining foo in except block
>>> foo()
'hello from backup foo'
>>>
If a module named “blah” had existed, the definition of foo would have been taken from there and
we would have seen “imported normally” printed out. Because no such module existed, foo was defined
in the except block, “defining foo in except block” was printed, and when we called foo, the ‘hello from
backup foo’ string was returned.
An Example Program
Here is the layout of a contrived but simple program that we will use to describe some aspects of
importing in Jython.
chapter8/
greetings.py
greet/
__init__.py
hello.py
153
www.it-ebooks.info
CHAPTER 8 ■ MODULES AND PACKAGES FOR CODE REUSE
people.py
This example contains one package: greet, which is a package because it is a directory containing
the special __init__.py file. Note that the directory chapter8 itself is not a package because it does not
contain an __init__.py. There are three modules in the example program: greetings, greet.hello, and
greet.people. The code for this program can be downloaded at
http://kenai.com/projects/jythonbook/sources/jython-book/show/src/chapter8.
greetings.py
print "in greetings.py"
import greet.hello
g = greet.hello.Greeter()
g.hello_all()
greet/__init__.py
print "in greet/__init__.py"
greet/hello.py
print "in greet/hello.py"
import greet.people as people
class Greeter(object):
def hello_all(self):
for name in people.names:
print "hello %s" % name
greet/people.py
print "in greet/people.py"
names = ["Josh", "Jim", "Victor", "Leo", "Frank"]
Trying Out the Example Code
If you run greetings.py in its own directory you get the following output:
$ jython greetings.py
in greetings.py
in greet/__init__.py
in greet/hello.py
in greet/people.py
hello Josh
hello Jim
hello Victor
hello Leo
hello Frank
154
www.it-ebooks.info
CHAPTER 8 ■ MODULES AND PACKAGES FOR CODE REUSE
There is a print statement at the top of each of the .py files to show the order of execution for the
modules. When run, the module greetings is loaded, printing out “in greetings.py.” Next it imports
greet.hello:
import greet.hello
Because this is the first time that the greet package has been imported, the code in __init__.py is
executed, printing “in greet/__init__.py”. Then the greet.hello module is executed, printing out “in
greet/hello.py.” The greet.hello module then imports the greet.people module, printing out “in
greet/people.py.” Now all of the imports are done, and greetings.py can create a greet.hello.Greeter class
and call its hello_all method.
Types of Import Statements
The import statement comes in a variety of forms that allow much finer control over how importing
brings named values into your current module.
import module
from module import submodule
from . import submodule
We will discuss each of the import statement forms in turn starting with:
import module
This most basic type of import imports a module directly. Unlike Java, this form of import binds the
left-most module name, so if you import a nested module like:
import greet.hello
you need to refer to it as “greet.hello” and not just “hello” in your code.
import greet.hello as foo
The “as foo” part of the import allows you to relabel the “greet.hello” module as “foo” to make it
more convenient to call. The example program uses this method to relabel “greet.hello” as “hello.” Note
that it is not important that “hello” was the name of the subpackage except that it might aid in reading
the code. You would also use this technique if the identifier of the thing you wanted to import was
already in use in this namespace: if you already had a variable called foo, and you wanted to import
something else called foo, you could do import foo as bar.
From Import Statements
from module import name
This form of import allows you to import modules, classes or functions nested in other modules. This
allows you to import code like this:
from greet import hello
In this case, it is important that “hello” is actually a submodule of greet. This is not a relabeling but
actually gets the submodule named “hello” from the greet namespace. You can also use the from style of
155
www.it-ebooks.info
CHAPTER 8 ■ MODULES AND PACKAGES FOR CODE REUSE
import to import all of the names in a module (except for those that start with an underscore) into your
current module using a *. This form of import is discouraged in the Python community, and is
particularly troublesome when importing from Java packages (in some cases it does not work) so you
should avoid its use. It looks like this:
from module import *
If you are not importing from a Java package, it is sometimes convenient to use this form to pull in
everything from another module.
Relative Import Statements
A new kind of import introduced in Python 2.5 is the explicit relative import. These import statements
use dots to indicate how far back you will walk from the current nesting of modules, with one dot
meaning the current module.
from
from
from
from
. import module
.. import module
.module import submodule
..module import submodule
Even though this style of importing has just been introduced, its use is discouraged. Explicit relative
imports are a reaction to the demand for implicit relative imports. If we had wanted to import the
Greeter class out of greet.hello so that it could be instantiated with just Greeter() instead of
greet.hello.Greeter we could have imported it like this:
from greet.hello import Greeter
If you wanted to import Greeter into the greet.people module, you could get away with:
from hello import Greeter
This is a relative import. Because greet.people is a sibling module of greet.hello, the “greet” can be
left out. This relative import style is deprecated and should not be used. Some developers like this style
so that imports will survive module restructuring, but these relative imports can be error prone because
of the possibility of name clashes. There is a new syntax that provides an explicit way to use relative
imports, though they too are still discouraged. The previous import statement would look like this:
from .hello import Greeter
Aliasing Import Statements
Any of the above imports can add an “as” clause to import a module but give it a new name.
import module as alias
from module import submodule as alias
from . import submodule as alias
This gives you enormous flexibility in your imports, so to go back to the greet.hello example, you
could issue:
import greet.hello as foo
156
www.it-ebooks.info
CHAPTER 8 ■ MODULES AND PACKAGES FOR CODE REUSE
And use foo in place of greet.hello.
Hiding Module Names
Typically when a module is imported, all of the names in the module are available to the importing
module. There are a couple of ways to hide these names from importing modules. Starting any name
with an underscore (_) will document these names as private. The names are still accessible, they are just
not imported when you import the names of a module with “from module import *”. The second way to
hide module names is to define a list named __all__, which should contain only those names that you
wish to have your module to expose. As an example here is the value of __all__ at the top of Jython’s OS
module:
__all__ = ["altsep", "curdir", "pardir", "sep", "pathsep",
"linesep", "defpath", "name", "path",
"SEEK_SET", "SEEK_CUR", "SEEK_END"]
Note that you can add to __all__ inside of a module to expand the exposed names of that module. In
fact, the os module in Jython does just this to conditionally expose names based on the operating system
that Jython is running on.
Module Search Path, Compilation, and Loading
Understanding Jython’s process of locating, compiling, and loading packages and modules is very
helpful in getting a deeper understanding of how things really work in Jython.
Java Import Example
We’ll start with a Java class which is on the CLASSPATH when Jython is started:
package com.foo;
public class HelloWorld {
public void hello() {
System.out.println("Hello World!");
}
public void hello(String name) {
System.out.printf("Hello %s!", name);
}
}
Here we manipulate that class from the Jython interactive interpreter:
>>> from com.foo import HelloWorld
>>> h = HelloWorld()
>>> h.hello()
Hello World!
>>> h.hello("frank")
Hello frank!
It’s important to note that, because the HelloWorld program is located on the Java CLASSPATH, it
did not go through the sys.path process we talked about before. In this case the Java class gets loaded
157
www.it-ebooks.info
CHAPTER 8 ■ MODULES AND PACKAGES FOR CODE REUSE
directly by the ClassLoader. Discussions of Java ClassLoaders are beyond the scope of this book. To read
more about ClassLoader see execution section of the Java language specification:
http://java.sun.com/docs/books/jls/second_edition/html/execution.doc.html.
Module Search Path and Loading
Understanding the process of module search and loading is more complicated in Jython than in either
CPython or Java, because Jython can search both Java’s CLASSPATH and Python’s path. We’ll start by
looking at Python’s path and sys.path. When you issue an import, sys.path defines the path that Jython
will use to search for the name you are trying to import. The objects within the sys.path list tell Jython
where to search for modules. Most of these objects point to directories, but there are a few special items
that can be in sys.path for Jython that are not just pointers to directories. Trying to import a file that does
not reside anywhere in the sys.path (and also cannot be found in the CLASSPATH) raises an ImportError
exception. Let’s fire up a command line and look at sys.path.
>>> import sys
>>> sys.path
['', '/Users/frank/jython/Lib', '__classpath__', '__pyclasspath__/',
'/Users/frank/jython/Lib/site-packages']
The first blank entry (‘‘) tells Jython to look in the current directory for modules. The second entry
points to Jython’s Lib directory that contains the core Jython modules. The third and fourth entries are
special markers that we will discuss later, and the last points to the site-packages directory where new
libraries can be installed when you issue setuptools directives from Jython (see Appendix A for more
about setuptools). The module that gets imported is the first one that is found along this path. Once a
module is found, no more searching is done.
>>> import sys
>>> sys.path.append("/Users/frank/lib/mysql-connector-java-5.1.6.jar")
>>> import com.mysql
*sys-package-mgr*: processing new jar, '/Users/frank/lib/mysql-connector-java-5.1.6.jar'
>>> dir(com.mysql)
['__name__', 'jdbc']
In this example, we added the mysql jar to the sys path, then when we tried to find com.mysql, the
jar was scanned. Note that “com.mysql” is a Java package that is found in mysql-connector-java5.1.6.jar.
Java Package Scanning
Although you can ask the Java SDK to give you a list of all of the packages known to a ClassLoader using:
java.lang.ClassLoader#getPackages()
there is no corresponding
java.lang.Package#getClasses()
This is unfortunate for Jython, because Jython users expect to be able to introspect the code they
use in powerful ways. For example, users expect to be able to call dir() on Java packages to see what they
contain:
158
www.it-ebooks.info
CHAPTER 8 ■ MODULES AND PACKAGES FOR CODE REUSE
>>> import java.util.zip
>>> dir(java.util.zip)
['Adler32', 'CRC32', 'CheckedInputStream', 'CheckedOutputStream', 'Checksum',
'DataFormatException', 'Deflater', 'DeflaterOutputStream', 'GZIPInputStream',
'GZIPOutputStream', 'Inflater', 'InflaterInputStream', 'ZipEntry', 'ZipException',
'ZipFile', 'ZipInputStream', 'ZipOutputStream', '__name__']
And the same can be done on Java classes to see what they contain:
>>> import java.util.zip
>>> dir(java.util.zip.ZipInputStream)
['__class__', '__delattr__', '__doc__', '__eq__', '__getattribute__', '__hash__',
'__init__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__str__', 'available', 'class', 'close', 'closeEntry', 'equals', 'getClass',
'getNextEntry', 'hashCode', 'mark', 'markSupported', 'nextEntry', 'notify', 'notifyAll',
'read', 'reset', 'skip', 'toString', 'wait']
Making this sort of introspection possible in the face of merged namespaces requires some major
effort the first time that Jython is started (and when jars or classes are added to Jython’s path at
runtime). If you have ever run a new install of Jython before, you will recognize the evidence of this
system at work:
*sys-package-mgr*: processing new jar, '/Users/frank/jython/jython.jar'
*sys-package-mgr*: processing new jar,
'/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/classes.jar'
*sys-package-mgr*: processing new jar,
'/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/ui.jar'
*sys-package-mgr*: processing new jar,
'/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/laf.jar'
...
*sys-package-mgr*: processing new jar,
'/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/lib/ext/sunjce_provider.jar
'
*sys-package-mgr*: processing new jar,
'/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/lib/ext/sunpkcs11.jar'
This is Jython scanning all of the jar files that it can find to build an internal representation of the
package and classes available on your JVM. This has the unfortunate side effect of making the first
startup on a new Jython installation painfully slow.
How Jython Finds the Jars and Classes to Scan
There are two properties that Jython uses to find jars and classes. These settings can be given to Jython
using commandline settings or the registry (see Appendix A). The two properties are:
python.packages.paths
python.packages.directories
These properties are comma separated lists of further registry entries that actually contain the
values the scanner will use to build its listing. You probably should not change these properties. The
properties that get pointed to by these properties are more interesting. The two that potentially make
sense to manipulate are:
159
www.it-ebooks.info
CHAPTER 8 ■ MODULES AND PACKAGES FOR CODE REUSE
java.class.path
java.ext.dirs
For the java.class.path property, entries are separated as the classpath is separated on the operating
system you are on (that is, “;” on Windows and “:” on most other systems). Each of these paths are
checked for a .jar or .zip and if they have these suffixes they will be scanned.
For the java.ext.dirs property, entries are separated in the same manner as java.class.path, but these
entries represent directories. These directories are searched for any files that end with .jar or .zip, and if
any are found they are scanned.
To control the jars that are scanned, you need to set the values for these properties. There are a
number of ways to set these property values, see Appendix A for more.
If you only use full class imports, you can skip the package scanning altogether. Set the system
property python.cachedir.skip to true or (again) pass in your own postProperties to turn it off.
Compilation
Despite the popular belief that Jython is “interpreted, not compiled,” in reality all Jython code is turned
into Java bytecode before execution. This Java bytecode is not always saved to disk, but when you see
Jython execute any code, even in an eval or an exec, you can be sure that bytecode is getting fed to the
JVM. The sole exception to this that we know of is the experimental pycimport module that we will
describe in the section on sys.meta_path below, which interprets CPython bytecodes instead of
producing Java bytecodes.
Python Modules and Packages versus Java Packages
The basic semantics of importing Python modules and packages versus the semantics of importing Java
packages into Jython differ in some important respects that need to be kept carefully in mind.
sys.path
When Jython tries to import a module, it will look in its sys.path in the manner described in the previous
section until it finds one. If the module it finds represents a Python module or package, this import will
display a “winner take all” semantic. That is, the first Python module or package that gets imported
blocks any other module or package that might subsequently get found on any lookups. This means that
if you have a module foo that contains only a name bar early in the sys.path, and then another module
also called foo that only contains a name baz, then executing “import foo” will only give you foo.bar and
not foo.baz.
This differs from the case when Jython is importing Java packages. If you have a Java package
org.foo containing bar, and a Java package org.foo containing baz later in the path, executing “import
org.foo” will merge the two namespaces so that you will get both org.foo.bar and org.foo.baz.
Just as important to keep in mind, if there is a Python module or package of a particular name in
your path that conflicts with a Java package in your path this will also have a winner-take-all effect. If the
Java package is first in the path, then that name will be bound to the merged Java packages. If the Python
module or package wins, no further searching will take place, so the Java packages with the clashing
names will never be found.
Naming Python Modules and Packages
Developers coming from Java will often make the mistake of modeling their Jython package structure the
same way that they model Java packages. Do not do this. The reverse url convention of Java is a great, we
160
www.it-ebooks.info
CHAPTER 8 ■ MODULES AND PACKAGES FOR CODE REUSE
would even say a brilliant convention for Java. It works very well indeed in the world of Java where these
namespaces are merged. In the Python world however, where modules and packages display the
winner-take-all semantic, this is a disastrous way to organize your code.
If you adopt this style for Python, say you are coming from “acme.com,” you would set up a package
structure like “com.acme.” If you try to use a library from your vendor xyz that is set up as “com.xyz,”
then the first of these on your path will take the “com” namespace, and you will not be able to see the
other set of packages.
Proper Python Naming
The Python convention is to keep namespaces as shallow as you can, and make your top level
namespace reasonably unique, whether it is a module or a package. In the case of acme and company
xyz, you might start your package structures with “acme” and “xyz” if you wanted to have these entire
codebases under one namespace (not necessarily the right way to go — better to organize by product
instead of by organization, as a general rule).
■ Note There are at least two sets of names that are particularly bad choices for naming modules or packages in
Jython. The first is any top level domain like org, com, net, us, name. The second is any of the domains that Java
the language has reserved for its top level namespaces: java, javax.
Advanced Import Manipulation
This section describes some advanced tools for dealing with the internal machinery of imports. It is
pretty advanced stuff that is rarely needed, but when you need it, you really need it.
Import Hooks
To understand the way that Jython imports Java classes you have to understand a bit about the Python
import protocol. We won’t get into every detail, for that you would want to look at PEP 302
http://www.python.org/dev/peps/pep-0302/.
Briefly, we first try any custom importers registered on sys.meta_path. If one of them is capable of
importing the requested module, allow that importer to handle it. Next, we try each of the entries on
sys.path. For each of these, we find the first hook registered on sys.path_hooks that can handle the path
entry. If we find an import hook and it successfully imports the module, we stop. If this did not work, we
try the builtin import logic. If that also fails, an ImportError is thrown. So let’s look at Jython’s
path_hooks.
sys.path_hooks
>>> import sys
>>> sys.path_hooks
[, ,
]
Each of these path_hooks entries specifies a path_hook that will attempt to import special files.
JavaImporter, as its name implies, allows the dynamic loading of Java packages and classes that are
161
www.it-ebooks.info
CHAPTER 8 ■ MODULES AND PACKAGES FOR CODE REUSE
specified at runtime. For example, if you want to include a jar at runtime you can execute the following
code:
>>> import sys
>>> sys.path.append("mysql-connector-java-5.1.6.jar")
>>> import com.mysql
*sys-package-mgr*: processing new jar, 'mysqlconnector-java-5.1.6.jar'
>>> dir(com.mysql)
['__name__', 'jdbc']
Note how the package scanning gets kicked off when “com.mysql” is imported, as evidenced by the
line starting with *sys-package-mgr*. Upon import, the JavaImporter scanned the new jar and allowed
the import to succeed.
sys.meta_path
Adding entries to sys.meta_path allows you to add import behaviors that will occur before any other
import is attempted, even the default builtin importing behavior. This can be a very powerful tool,
allowing you to do all sorts of interesting things. As an example, we will talk about an experimental
module that ships with Jython 2.5. That module is pycimport. If you start up Jython and issue
>>> import pycimport
Jython will start scanning for .pyc files in your path and, if it finds one, it will use the .pyc file to load
your module.pyc files. These are the files that CPython produces when it compiles Python source code.
So, after you have imported pycimport (which adds a hook to sys.meta_path) then issue:
>>> import foo
Jython will scan your path for a file named foo.pyc, and if it finds one it will import the foo module
using the CPython bytecodes. It does this by creating a special class that defines a find_module method
that specifies how to load in a pyc file. This class is then added to the meta search path with the
sys.meta_path.insert method. The find_module method calls into other parts of pycimport and looks for
.pyc files. If it finds one, it knows how to parse and execute those files and adds the corresponding
module to the runtime. Pretty cool, eh?
Summary
In this chapter, you have learned how to divide code up into modules to for the purpose of organization
and reuse. We have learned how to write modules and packages, and how the Jython system interacts
with Java classes and packages. This ends Part I. We have now covered the basics of the Jython language
and are now ready to learn how to use Jython.
162
www.it-ebooks.info
C H A P T E R 10
■■■
P A R T
II
■■■
Using the Language
163
www.it-ebooks.info
CHAPTER 10 ■ DELEGATES, ANONYMOUS FUNCTIONS, AND EVENTS
164
www.it-ebooks.info
CHAPTER 9
■■■
Scripting With Jython
In this chapter, we will look at scripting with Jython. For our purposes, we will define “scripting” as the
writing of small programs to help out with daily tasks. These tasks are things like deleting and creating
directories, managing files and programs, and anything else that feels repetitive that you might be able
to express as a small program. In practice, however, scripts can become so large that the line between a
script and a full sized program can blur.
We’ll start with some very small examples to give you a feel for the sorts of tasks you might script
from Jython. Then we'll cover a medium-sized task to show the use of a few of these techniques together.
Getting the Arguments Passed to a Script
All but the simplest of scripts will take some arguments from the command line. We’ll start our look at
scripting by printing out any args passed to our script.
Listing 9-1.
import sys
for arg in sys.argv:
print arg
Let’s try running our script with some random arguments:
Listing 9-2.
$ jython args.py a b c 1 2 3
args.py
a
b
c
1
2
3
The first value in sys.argv is the name of the script itself (args.py), the rest is the items passed in on
the command line.
165
www.it-ebooks.info
CHAPTER 9 ■ SCRIPTING WITH JYTHON
Searching for a File
Many scripting tasks take the form of “find a bunch of files and do something with them.” So let’s take a
look at how you might find some files from a Jython program. We’ll start with a simple script that finds
any files in your current directory that match a passed in string:
Listing 9-3.
import sys
import os
for f in os.listdir(sys.argv[1]):
if f.find(sys.argv[2]) != -1:
print f
At the top of the script, we import the sys and os modules. Then we run a for loop over the results of
os.listdir(sys.argv[1]). The os module is a good place to look if you are trying to accomplish the sorts of
tasks you might do on a command prompt, such as listing the files in a directory, deleting a file,
renaming a file, and the like. The listdir function of the os module takes one argument: a string that will
be used as the path. The entries of the directory on that path are returned as a list. In this case, if we run
this in its own directory (by passing in “.” for the current directory), we see:
Listing 9-4.
$ ls
args.py
search.py
$ jython list.py . py
args.py
search.py
$ jython list.py . se
search.py
In the first call to list.py, we list all files that contain “py”, listing “args.py” and “search.py.” In the
second call, we list all files that contain the string “se”, so only “search.py” is listed.
The os module contains many useful functions and attributes that can be used to get information
about your operating environment. Next we can open up a Jython prompt and try out a few os features:
Listing 9-5.
>>> import os
>>> os.getcwd()
'/Users/frank/Desktop/frank/hg/jythonbook~jython-book/src/chapter8'
>>> os.chdir("/Users/frank")
>>> os.getcwd()
'/Users/frank'
We just printed out our current working directory with os.getcwd(), changed our current working
directory to “/Users/frank,” and then printed out the new directory with another call to os.getcwd(). It is
important to note that the JVM does not expose the ability to actually change the current working
directory of the process running Jython. For this reason, Jython keeps track of its own current working
166
www.it-ebooks.info
CHAPTER 9 ■ SCRIPTING WITH JYTHON
directory. As long as you stay within Jython’s standard library, the current working directory will behave
as you expect (it will be changed with os.chdir()). However, if you import Java library functions that
depend on a current working directory, it will always reflect the directory that Jython was started in.
Listing 9-6.
>>> import os
>>> os.getcwd()
'/Users/frank/Desktop/frank/hg/jythonbook~jython-book/src/chapter8'
>>> from java.io import File
>>> f = File(".")
>>> for x in f.list():
...
print x
...
args.py
search.py
>>> os.chdir("/Users/frank")
>>> os.getcwd()
'/Users/frank'
>>> os.listdir(".")
['Desktop', 'Documents', 'Downloads', 'Dropbox', 'Library', 'Movies', 'Music', 'Pictures',
'Public', 'Sites']
>>> g = File(".")
>>> for x in g.list():
...
print x
...
args.py
search.py
Quite a bit went on in that last example, we’ll take it step by step. We imported os and printed the
current working directory, which is chapter8. We imported the File class from java.io. We then printed
the contents of “.” from the Java side of the world. We then changed directories with os.chdir() to the
home directory, and listed the contents of “.” from Jython’s perspective, and listed “.” from the Java
perspective. The important thing to note is that “.” from Java will always see the chapter8 directory
because we cannot change the real working directory of the Java process—we can only keep track of a
working directory so that Jython’s working directory behaves the way Python programmers expect. Too
many Python tools (like distutils and setuptools) depend on the ability to change working directories to
ignore.
Manipulating Files
Listing files is great, but a more interesting scripting problem is actually doing something to the files you
are working with. One of these problems that comes up for me from time to time is that of changing the
extensions of a bunch of files. If you need to change one or two extensions, it isn’t a big deal to do it
manually. If you want to change hundreds of extensions, things get very tedious. Splitting extensions can
be handled with the splitext function from the os.path module. The splitext function takes a file name
and returns a tuple of the base name of the file and the extension.
167
www.it-ebooks.info
CHAPTER 9 ■ SCRIPTING WITH JYTHON
Listing 9-7.
>>> import os
>>> for f in os.listdir("."):
...
print os.path.splitext(f)
...
('args', '.py')
('builder', '.py')
('HelloWorld', '.java')
('search', '.py')
Now that we can get the extensions, we just need to be able to rename the files. Luckily, the os
module has exactly the function we need, rename:
Listing 9-8.
>>> import os
>>> os.rename('HelloWorld.java', 'HelloWorld.foo')
>>> os.listdir('.')
['args.py', 'builder.py', 'HelloWorld.foo', 'search.py']
If you are manipulating any important files, be sure to put the names back!
>>> os.rename('HelloWorld.foo', 'HelloWorld.java')
>>> os.listdir('.')
['args.py', 'builder.py', 'HelloWorld.java', 'search.py']
Now that you know how to get extensions and how to rename files, we can put them together into a
script (chext.py) that changes extensions:
Listing 9-9.
import sys
import os
for f in os.listdir(sys.argv[1]):
base, ext = os.path.splitext(f)
if ext[1:] == sys.argv[2]:
os.rename(f, "%s.%s" % (base, sys.argv[3]))
Making a Script a Module
If you wanted to turn chext.py into a module that could also be used from other modules, you could put
this code into a function and separate its use as a script like this:
168
www.it-ebooks.info
CHAPTER 9 ■ SCRIPTING WITH JYTHON
Listing-9-10.
import sys
import os
def change_ext(directory, old_ext, new_ext):
for f in os.listdir(sys.argv[1]):
base, ext = os.path.splitext(f)
if ext[1:] == sys.argv[2]:
os.rename(f, "%s.%s" % (base, sys.argv[3]))
if __name__ == '__main__':
if len(sys.argv) < 4:
print "usage: %s directory old_ext new_ext" % sys.argv[0]
sys.exit(1)
change_ext(sys.argv[1], sys.argv[2], sys.argv[3])
This new version can be used from an external module like this:
Listing 9-11.
import chext
chext.change_ext(".", "foo", "java")
We have also used this change to introduce a little error checking, if we haven’t supplied enough
arguments, the script prints out a usage message.
Parsing Commandline Options
Many scripts are simple one-offs that you write once, use, and forget. Others become part of your weekly
or even daily use over time. When you find that you are using a script over and over again, you often find
it helpful to pass in command line options. There are three main ways that this is done in Jython. The
first way is to hand parse the arguments that can be found from sys.argv as we did above in chext.py, the
second is the getopt module, and the third is the newer, more flexible optparse module.
If you are going to do more than just feed the arguments to your script directly, then parsing these
arguments by hand can get pretty tedious, and you’ll be much better off using getopt or optparse. The
optparse module is the newer, more flexible option, so we'll cover that one. The getopt module is still
useful since it requires a little less code for simpler expected arguments. Here is a basic optparse script:
Listing 9-12.
# script foo3.py
from optparse import optionparser
parser = optionparser()
parser.add_option("-f", "--foo", help="set foo option")
parser.add_option("-b", "--bar", help="set bar option")
(options, args) = parser.parse_args()
print "options: %s" % options
print "args: %s" % args
running the above:
169
www.it-ebooks.info
CHAPTER 9 ■ SCRIPTING WITH JYTHON
Listing 9-13.
$ jython foo3.py -b a --foo b c d
$ options: {'foo': 'b', 'bar': 'a'}
$ args: ['c', 'd']
In this example, we have created an optionparser and added two options with the add_option
method. The add_option method takes at least one string as an option argument (“-f” in the first case)
and an optional long version (“--foo” in the previous case). You can then pass in optional keyword
options like the “help” option that sets the help string that will be associated with the script. We’ll come
back to the optparse module with a more concrete example later in this chapter.
Compiling Java Source
While compiling Java source is not strictly a typical scripting task, it is a task that we’d like to show off in
a bigger example starting in the next section. The API we are about to cover was introduced in jdk 6, and
is optional for jvm vendors to implement. We know that it works on the jdk 6 from Sun (the most
common JDK in use) and on the jdk 6 that ships with mac os x. For more details of the javacompiler api,
a good starting point is here: http://java.sun.com/javase/6/docs/api/javax/tools/javacompiler.html.
The following is a simple example of the use of this API from Jython:
Listing 9-14.
from javax.tools import (ForwardingJavaFileManager, ToolProvider,
DiagnosticCollector,)
names = ["HelloWorld.java"]
compiler = ToolProvider.getSystemJavaCompiler()
diagnostics = DiagnosticCollector()
manager = compiler.getStandardFileManager(diagnostics, none, none)
units = manager.getJavaFileObjectsFromStrings(names)
comp_task = compiler.getTask(none, manager, diagnostics, none, none, units)
success = comp_task.call()
manager.close()
First we import some Java classes from the javax.tools package. Then we create a list containing just
one string, “HelloWorld.java.” Then we get a handle on the system Java compiler and call it “compiler.”
A couple of objects that need to get passed to our compiler task, “diagnostics” and “manager” are
created. We turn our list of strings into “units” and finally we create a compiler task and execute its call
method. If we wanted to do this often, we’d probably want to roll up all of this into a simple method.
Example Script: Builder.py
So we’ve discussed a few of the modules that tend to come in handy when writing scripts for Jython.
Now we’ll put together a simple script to show off what can be done. We’ve chosen to write a script that
will help handle the compilation of java files to .class files in a directory, and clean the directory of .class
files as a separate task. We will want to be able to create a directory structure, delete the directory
structure for a clean build, and of course compile our java source files.
170
www.it-ebooks.info
CHAPTER 9 ■ SCRIPTING WITH JYTHON
Listing 9-15.
import os
import sys
import glob
from javax.tools import (forwardingjavafilemanager, toolprovider,
diagnosticcollector,)
tasks = {}
def task(func):
tasks[func.func_name] = func
@task
def clean():
files = glob.glob("*.class")
for file in files:
os.unlink(file)
@task
def compile():
files = glob.glob("*.java")
_log("compiling %s" % files)
if not _compile(files):
quit()
_log("compiled")
def _log(message):
if options.verbose:
print message
def _compile(names):
compiler = toolprovider.getsystemjavacompiler()
diagnostics = diagnosticcollector()
manager = compiler.getstandardfilemanager(diagnostics, none, none)
units = manager.getjavafileobjectsfromstrings(names)
comp_task = compiler.gettask(none, manager, diagnostics, none, none, units)
success = comp_task.call()
manager.close()
return success
if __name__ == '__main__':
from optparse import optionparser
parser = optionparser()
parser.add_option("-q", "--quiet",
action="store_false", dest="verbose", default=true,
help="don't print out task messages.")
parser.add_option("-p", "--projecthelp",
action="store_true", dest="projecthelp",
help="print out list of tasks.")
(options, args) = parser.parse_args()
171
www.it-ebooks.info
CHAPTER 9 ■ SCRIPTING WITH JYTHON
if options.projecthelp:
for task in tasks:
print task
sys.exit(0)
if len(args) < 1:
print "usage: jython builder.py [options] task"
sys.exit(1)
try:
current = tasks[args[0]]
except KeyError:
print "task %s not defined." % args[0]
sys.exit(1)
current()
The script defines a “task” decorator that gathers the names of the functions and puts them in a
dictionary. We have an optionparser class that defines two options --projecthelp and --quiet. By default
the script logs its actions to standard out. The option --quiet turns this logging off, and --projecthelp lists
the available tasks. We have defined two tasks, “compile” and “clean.” The “compile” task globs for all of
the .java files in your directory and compiles them. The “clean” task globs for all of the .class files in your
directory and deletes them. Do be careful! The .class files are deleted without prompting!
So let’s give it a try. If you create a Java class in the same directory as builder.py, say the classic
“Hello World” program:
HelloWorld.java
Listing 9-16.
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World");
}
}
You could then issue these commands to builder.py with these results:
Listing 9-17.
[frank@pacman chapter8]$ jython builder.py --help
Usage: builder.py [options]
Options:
-h, --help
show this help message and exit
-q, --quiet
Don't print out task messages.
-p, --projecthelp Print out list of tasks.
[frank@pacman chapter8]$ jython builder.py --projecthelp
compile
clean
172
www.it-ebooks.info
CHAPTER 9 ■ SCRIPTING WITH JYTHON
[frank@pacman chapter8]$ jython builder.py compile
compiling ['HelloWorld.java']
compiled
[frank@pacman chapter8]$ ls
HelloWorld.java HelloWorld.class builder.py
[frank@pacman chapter8]$ jython builder.py clean
[frank@pacman chapter8]$ ls
HelloWorld.java builder.py
[frank@pacman chapter8]$ jython builder.py --quiet compile
[frank@pacman chapter8]$ ls
HelloWorld.class HelloWorld.java builder.py
[frank@pacman chapter8]$
Summary
This chapter has shown how to create scripts with Jython. We have gone from the most simple one- and
two-line scripts to large scripts with lots of optional inputs. We hope this will help you create your own
tools to help automate some of the repetition out of your days.
173
www.it-ebooks.info
CHAPTER 9 ■ SCRIPTING WITH JYTHON
174
www.it-ebooks.info
C H A P T E R 10
■■■
Jython and Java Integration
Java integration is the heart of Jython application development. Most Jython developers are either
Python developers that are looking to make use of the vast library of tools that the JVM has to offer, or
Java developers that would like to utilize the Python language semantics without migrating to a
completely different platform. The fact is that most Jython developers are using it so that they can take
advantage of the vast libraries available to the Java world, and in order to do so there needs to be a
certain amount of Java integration in the application. Whether you plan to use some of the existing Java
libraries in your application, or you’re interested in mixing some great Python code into your Java
application, this chapter is geared to help with the integration.
This chapter will focus on integrating Java and Python, but it will explore several different angles on
the topic. You will learn several techniques to make use Jython code within your Java applications.
Perhaps you’d like to simplify your code a bit; this chapter will show you how to write certain portions of
your code in Jython and others in Java so that you can make code as simple as possible.
You’ll also learn how to make use of the many Java libraries within your Jython applications while
using Pythonic syntax! Forget about coding those programs in Java: why not use Jython so that the Java
implementations in the libraries are behind the scenes? This chapter will show how to write Python code
and use the libraries directly from it.
Using Java Within Jython Applications
Making use of Java from within Jython applications is about as seamless as using external Jython
modules within a Jython script. As you learned in Chapter 8, you can simply import the required Java
classes and use them directly. Java classes can be called in the same fashion as Jython classes, and the
same goes for method calling. You simply call a class method and pass parameters the same way you’d
do in Python.
Type coercion occurs much as it does when using Jython in Java in order to seamlessly integrate the
two languages. In the following table, you will see the Java types that are coerced into Python types and
how they match up. Table 10-1 was taken from the Jython user guide.
Table 10-1. Python and Java Types
Java Type
Python Type
char
String(length of 1)
boolean
Integer(True = not zero)
175
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
Table 10-1. Python and Java Types (continued)
Java Type
Python Type
byte, short, int, long
Integer
java.lang.String, byte[], char[]
String
java.lang.Class
JavaClass
Foo[]
Array(containing objects of class or subclass of Foo)
java.lang.Object
String
orb.python.core.PyObject
Unchanged
Foo
class Foo
Another thing to note about the utilization of Java within Jython is that there may be some naming
conflicts. If a Java object conflicts with a Python object name, then you can simply fully qualify the Java
object in order to ensure that the conflict is resolved. Another technique which was also discussed in
Chapter 8 is making use of the “as” keyword when importing in order to rename an imported piece of
code.
In the next couple of examples, you will see some Java objects being imported and used from within
Jython.
Listing 10-1. Using Java in Jython
>>> from java.lang import Math
>>> Math.max(4, 7)
7L
>>> Math.pow(10,5)
100000.0
>>> Math.round(8.75)
9L
>>> Math.abs(9.765)
9.765
>>> Math.abs(-9.765)
9.765
>>> from java.lang import System as javasystem
>>> javasystem.out.println("Hello")
Hello
Now let’s create a Java object and use it from within a Jython application.
Beach.java
public class Beach {
private String name;
private String city;
176
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
public Beach(String name, String city){
this.name = name;
this.city = city;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
Using Beach.java in Jython
>>> import Beach
>>> beach = Beach("Cocoa Beach","Cocoa Beach")
>>> beach.getName()
u'Cocoa Beach'
>>> print beach.getName()
Cocoa Beach
As we had learned in Chapter 8, one thing you’ll need to do is ensure that the Java class you wish to
use resides within your CLASSPATH. In the example above, I created a JAR file that contained the Beach
class and then put that JAR on the CLASSPATH.
It is also possible to extend or subclass Java classes via Jython classes. This allows us to extend the
functionality of a given Java class using Jython objects, which can be quite helpful at times. The next
example shows a Jython class extending a Java class that includes some calculation functionality. The
Jython class then adds another calculation method and makes use of the calculation methods from both
the Java class and the Jython class.
Listing 10-2. Extending Java Classes
Calculator.java
/**
* Java calculator class that contains two simple methods
*/
public class Calculator {
public Calculator(){
}
177
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
public double calculateTip(double cost, double tipPercentage){
return cost * tipPercentage;
}
public double calculateTax(double cost, double taxPercentage){
return cost * taxPercentage;
}
}
JythonCalc.py
import Calculator
from java.lang import Math
class JythonCalc(Calculator):
def __init__(self):
pass
def calculateTotal(self, cost, tip, tax):
return cost + self.calculateTip(tip) + self.calculateTax(tax)
if __name__ == "__main__":
calc = JythonCalc()
cost = 23.75
tip = .15
tax = .07
print "Starting Cost: ", cost
print "Tip Percentage: ", tip
print "Tax Percentage: ", tax
print Math.round(calc.calculateTotal(cost, tip, tax))
Result
Starting Cost: 23.75
Tip Percentage: 0.15
Tax Percentage: 0.07
29
Using Jython Within Java Applications
Often, it is handy to have the ability to make use of Jython from within a Java application. Perhaps there
is a class that would be better implemented in Python syntax, such as a Javabean. Or maybe there is a
handy piece of Jython code that would be useful within some Java logic. Whatever the case may be, there
are several approaches you can use in order to achieve this combination of technologies. In this section,
we’ll cover some of the older techniques for using Jython within Java, and then go into the current and
future best practices for doing this. In the end, you should have a good understanding for how to use a
module, script, or even just a few lines of Jython within your Java application. You will also have an
overall understanding for the way that Jython has evolved in this area.
178
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
Object Factories
Perhaps the most widely used technique used today for incorporating Jython code within Java
applications is the object factory design pattern. This idea basically enables seamless integration
between Java and Jython via the use of object factories. There are different implementations of the logic,
but all of them do have the same result in the end.
Implementations of the object factory paradigm allow one to include Jython modules within Java
applications without the use of an extra compilation step. Moreover, this technique allows for a clean
integration of Jython and Java code through usage of Java interfaces. In this section, I will explain the
main concept of the object factory technique and then I will show you various implementations.
Let’s take a look at an overview of the entire procedure from a high level. Say that you’d like to use one of
your existing Jython modules as an object container within a Java application. Begin by coding a Java
interface that contains definitions for those methods contained in the module that you’d like to expose
to the Java application. Next, you would modify the Jython module to implement the newly coded Java
interface. After this, code a Java factory class that would make the necessary conversions of the module
from a PyObject into a Java object. Lastly, take the newly created Java object and use it as you wish. It
may sound like a lot of steps in order to perform a simple task, but I think you’ll agree that it is not very
difficult once you’ve seen it in action.
Over the next few sections, I will take you through different examples of the implementation. The
first example is a simple and elegant approach that involves a one-to-one Jython object and factory
mapping. In the second example, we’ll take a look at a very loosely coupled approach for working with
object factories that basically allows one factory to be used for all Jython objects. Each of these
methodologies has its own benefit and you can use the one that works best for you.
One-to-One Jython Object Factories
We will first discuss the notion of creating a separate object factory for each Jython object we wish to
use. This one-to-one technique can prove to create lots of boilerplate code, but it has some advantages
that we’ll take a closer look at later on. In order to utilize a Jython module using this technique, you must
either ensure that the .py module is contained within your sys.path, or hard code the path to the module
within your Java code. Let’s take a look at an example of this technique in use with a Java application
that uses a Jython class representing a building.
Listing 10-3. Creating a One-To-One Object Factory
Building.py
# A python module that implements a Java interface to
# create a building object
from org.jython.book.interfaces import BuildingType
class Building(BuildingType):
def __init__(self, name, address, id):
self.name = name
self.address = address
self.id = id
def getBuildingName(self):
return self.name
def getBuildingAddress(self):
return self.address
def getBuldingId(self):
179
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
return self.id
We begin with a Jython module named Building.py that is placed somewhere on our sys.path. Now,
we must first ensure that there are no name conflicts before doing so or we could see some quite
unexpected results. It is usually a safe bet to place this file at the source root for your application unless
you explicitly place the file in your sys.path elsewhere. You can see that our Building.py object is a
simple container for holding building information. We must explicitly implement a Java interface within
our Jython class. This will allow the PythonInterpreter to coerce our object later. Our second piece of
code is the Java interface that we implemented in Building.py. As you can see from the code, the
returning Jython types are going to be coerced into Java types, so we define our interface methods using
the eventual Java types. Let’s take a look at the Java interface next.
BuildingType.java
// Java interface for a building object
package org.jython.book.interfaces;
public interface BuildingType {
public String getBuildingName();
public String getBuildingAddress();
public String getBuildingId();
}
Looking through the definitions contained within the Java interface, it is plain to see that the python
module that subclasses it simply implements each of the definitions. If we wanted to change the python
code a bit and add some code to one of the methods we could do so without touching the Java interface.
The next piece of code that we need is a factory written in Java. This factory has the job of coercing the
python module into a Java class.
BuildingFactory.java
/**
*
* Object Factory that is used to coerce python module into a
* Java class
*/
package org.jython.book.util;
import
import
import
import
org.jython.book.interfaces.BuildingType;
org.python.core.PyObject;
org.python.core.PyString;
org.python.util.PythonInterpreter;
public class BuildingFactory {
private PyObject buildingClass;
/**
*
*
*
*
*
*
Create a new PythonInterpreter object, then use it to
execute some python code. In this case, we want to
import the python module that we will coerce.
Once the module is imported than we obtain a reference to
it and assign the reference to a Java variable
180
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
*/
public BuildingFactory() {
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.exec("from Building import Building");
buildingClass = interpreter.get("Building");
}
/**
* The create method is responsible for performing the actual
* coercion of the referenced python module into Java bytecode
*/
public BuildingType create (String name, String location, String id) {
PyObject buildingObject = buildingClass.__call__(new PyString(name),
new PyString(location),
new PyString(id));
return (BuildingType)buildingObject.__tojava__(BuildingType.class);
}
}
The third piece of code in the example above plays a most important role, since this is the object
factory that will coerce our Jython code into a resulting Java class. In the constructor, a new instance of
the PythonInterpreter is created. We then utilize the interpreter to obtain a reference to our Jython
object and store it into our PyObject. Next, there is a static method named create that will be called in
order to coerce our Jython object into Java and return the resulting class. It does so by performing a
__call__ on the PyObject wrapper itself, and as you can see we have the ability to pass parameters to it if
we like. The parameters must also be wrapped by PyObjects. The coercion takes place when the
__tojava__ method is called on the PyObject wrapper. In order to make object implement our Java
interface, we must pass the interface EmployeeType.class to the __tojava__ call.
Main.java
package org.jython.book;
import org.jython.book.util.BuildingFactory;
import org.jython.book.interfaces.BuildingType;
public class Main {
private static void print(BuildingType building) {
System.out.println("Building Info: " +
building.getBuildingId() + " " +
building.getBuildingName() + " " +
building.getBuildingAddress());
}
/**
* Create three building objects by calling the create() method of
* the factory.
*/
public static void main(String[] args) {
BuildingFactory factory = new BuildingFactory();
print(factory.create("BUILDING-A", "100 WEST MAIN", "1"));
print(factory.create("BUILDING-B", "110 WEST MAIN", "2"));
181
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
print(factory.create("BUILDING-C", "120 WEST MAIN", "3"));
}
}
The last bit of provided code, Main.java, shows how to make use of our factory. You can see that the
factory takes care of all the heavy lifting and our implementation in Main.java is quite small. Simply call
the factory.create() method to instantiate a new PyObject and coerce it into Java.
This procedure for using the object factory design has the benefit of maintaining complete
awareness of the Jython object from within Java code. In other words, creating a separate factory for
each Jython object allows for the use of passing arguments into the constructor of the Jython object.
Since the factory is being designed for a specific Jython object, we can code the __call__ on the PyObject
with specific arguments that will be passed into the new constructor of the coerced Jython object. Not
only does this allow for passing arguments into the constructor, but also increases the potential for good
documentation of the object since the Java developer will know exactly what the new constructor will
look like. The procedures performed in this subsection are probably the most frequently used
throughout the Jython community. In the next section, we’ll take a look at the same technique applied to
a generic object factory that can be used by any Jython object.
Summary of One-to-One Object Factory
The key to this design pattern is the creation of a factory method that utilizes PythonInterpreter in order
to load the desired Jython module. Once the factory has loaded the module via PythonInterpreter, it
creates a PyObject instance of the module. Lastly, the factory coerces the PyObject into Java code using
the PyObject __tojava__ method.
Overall, the idea is not very difficult to implement and relatively straightforward. However, the
different implementations come into play when it comes to passing references for the Jython module
and a corresponding Java interface. It is important to note that the factory takes care of instantiating the
Jython object and translating it into Java. All work that is performed against the resulting Java object is
coded against a corresponding Java interface. This is a great design because it allows us to change the
Jython code implementation if we wish without altering the definition contained within the interface.
The Java code can be compiled once and we can change the Jython code at will without breaking the
application.
Making Use of a Loosely Coupled Object Factory
The object factory design does not have to be implemented using a one to one strategy such as that
depicted in the example above. It is possible to design the factory in such a way that it is generic enough
to be utilized for any Jython object. This technique allows for less boilerplate coding as you only require
one Singleton factory that can be used for all Jython objects. It also allows for ease of use as you can
separate the object factory logic into its own project and then apply it wherever you’d like. For instance,
I’ve created a project named PlyJy (http://kenai.com/projects/plyjy) that basically contains a Jython
object factory that can be used in any Java application in order to create Jython objects from Java
without worrying about the factory. You can go to Kenai and download it now to begin learning about
loosely coupled object factories. In this section we’ll take a look at the design behind this project and
how it works.
Let’s take a look at the same example from above and apply the loosely coupled object factory
design. You will notice that this technique forces the Java developer to do a bit more work when creating
the object from the factory, but it has the advantage of saving the time that is spent to create a separate
factory for each Jython object. You can also see that now we need to code setters into our Jython object
and expose them via the Java interface as we can no longer make use of the constructor for passing
arguments into the object since the loosely coupled factory makes a generic __call__ on the PyObject.
182
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
Listing 10-4. Using a Loosely Coupled Object Factory
Building.py
from org.jython.book.interfaces import BuildingType
#
Building object that subclasses a Java interface
class Building(BuildingType):
def __init__(self):
self.name = None
self.address = None
self.id = -1
def getBuildingName(self):
return self.name
def setBuildingName(self, name):
self.name = name;
def getBuildingAddress(self):
return self.address
def setBuildingAddress(self, address):
self.address = address
def getBuildingId(self):
return self.id
def setBuildingId(self, id):
self.id = id
If we follow this paradigm then you can see that our Jython module must be coded a bit differently
than it was in our one-to-one example. The main differences are in the initializer as it no longer takes
any arguments, and we therefore have coded setter methods into our object. The rest of the concept still
holds true in that we must implement a Java interface that will expose those methods we wish to invoke
from within our Java application. In this case, we coded the BuildingType.java interface and included
the necessary setter definitions so that we have a way to load our class with values.
BuildingType.java
package org.jython.book.interfaces;
/**
* Java interface defining getters and setters
*/
public interface BuildingType {
public
public
public
public
public
String getBuildingName();
String getBuildingAddress();
int getBuildingId();
void setBuildingName(String name);
void setBuildingAddress(String address);
183
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
public void setBuildingId(int id);
}
Our next step is to code a loosely coupled object. If you take a look at the code in the
JythonObjectFactory.java class you will see that it is a singleton; that is it can only be instantiated one
time. The important method to look at is createObject() as it does all of the work.
JythonObjectFactory.java
import
import
import
import
java.util.logging.Level;
java.util.logging.Logger;
org.python.core.PyObject;
org.python.util.PythonInterpreter;
/**
* Object factory implementation that is defined
* in a generic fashion.
*
*/
public class JythonObjectFactory {
private static JythonObjectFactory instance = null;
private static PyObject pyObject = null;
protected JythonObjectFactory() {
}
/**
* Create a singleton object. Only allow one instance to be created
*/
public static JythonObjectFactory getInstance(){
if(instance == null){
instance = new JythonObjectFactory();
}
return instance;
}
/**
* The createObject() method is responsible for the actual creation of the
* Jython object into Java bytecode.
*/
public static Object createObject(Object interfaceType, String moduleName){
Object javaInt = null;
// Create a PythonInterpreter object and import our Jython module
// to obtain a reference.
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.exec("from " + moduleName + " import " + moduleName);
pyObject = interpreter.get(moduleName);
try {
184
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
// Create a new object reference of the Jython module and
// store into PyObject.
PyObject newObj = pyObject.__call__();
// Call __tojava__ method on the new object along with the interface name
// to create the java bytecode
javaInt = newObj.__tojava__(Class.forName(interfaceType.toString().substring(
interfaceType.toString().indexOf(" ")+1,
interfaceType.toString().length())));
} catch (ClassNotFoundException ex) {
Logger.getLogger(JythonObjectFactory.class.getName()).log(Level.SEVERE, null,
ex);
}
return javaInt;
}
}
As you can see from the code, the PythonInterpreter is responsible for obtaining a reference to the
Jython object name that we pass as a String value into the method. Once the PythonInterpreter has
obtained the object and stored it into a PyObject, its __call__() method is invoked without any
parameters. This will retrieve an empty object that is then stored into another PyObject referenced by
newObj. Lastly, our newly obtained object is coerced into Java code by calling the __tojava__() method
which takes the fully qualified name of the Java interface we’ve implemented with our Jython object. The
new Java object is then returned.
Main.java
import
import
import
import
import
java.io.IOException;
java.util.logging.Level;
java.util.logging.Logger;
org.jythonbook.interfaces.BuildingType;
org.jybhonbook.factory.JythonObjectFactory;
public class Main {
public static void main(String[] args) {
// Obtain an instance of the object factory
JythonObjectFactory factory = JythonObjectFactory.getInstance();
// Call the createObject() method on the object factory by
// passing the Java interface and the name of the Jython module
// in String format. The returning object is casted to the the same
// type as the Java interface and stored into a variable.
BuildingType building = (BuildingType) factory.createObject(
BuildingType.class, "Building");
// Populate the object with values using the setter methods
building.setBuildingName("BUIDING-A");
building.setBuildingAddress("100 MAIN ST.");
building.setBuildingId(1);
System.out.println(building.getBuildingId() + " " + building.getBuildingName() + " "
+
building.getBuildingAddress());
185
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
}
}
Taking a look at the Main.java code, you can see that the factory is instantiated or referenced via the
use of the JythonObjectFactory.getInstance(). Once we have an instance of the factory, the
createObject(Interface, String) is called passing the interface and a string representation of the module
name we wish to use. The code must cast the coerced object using the interface as well. This example
assumes that the object resides somewhere on your sys.path, otherwise you can use the
createObjectFromPath(Interface, String) that accepts the string representation for the path to the module
we’d like to coerce. This is of course not a preferred technique since it will now include hard-coded
paths, but it can be useful to apply this technique for testing purposes. For example if you’ve got two
Jython modules coded and one of them contains a different object implementation for testing purposes,
then this technique will allow you to point to the test module.
More Efficient Version of Loosely Coupled Object Factory
Another similar, yet, more refined implementation omits the use of PythonInterpreter and instead
makes use of PySystemState. Why would we want another implementation that produces the same
results? Well, there are a couple of reasons. The loosely coupled object factory design I described in the
beginning of this section instantiates the PythonInterpreter and then makes calls against it. This can
cause a decrease in performance, as it is quite expensive to use the interpreter. On the other hand, we
can make use of PySystemState and save ourselves the trouble of incurring extra overhead making calls
to the interpreter. Not only does the next example show how to utilize this technique, but it also shows
how we can make calls upon the coerced object and pass arguments at the same time.
Listing 10-5. Use PySystemState to Code a Loosely Coupled Factory
JythonObjectFactory.java
package org.jython.book.util;
import org.python.core.Py;
import org.python.core.PyObject;
import org.python.core.PySystemState;
/**
* Jython Object Factory using PySystemState
*/
public class JythonObjectFactory {
private final Class interfaceType;
private final PyObject klass;
// Constructor obtains a reference to the importer, module, and the class name
public JythonObjectFactory(PySystemState state, Class interfaceType, String moduleName,
String className) {
this.interfaceType = interfaceType;
PyObject importer = state.getBuiltins().__getitem__(Py.newString("__import__"));
186
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
PyObject module = importer.__call__(Py.newString(moduleName));
klass = module.__getattr__(className);
System.err.println("module=" + module + ",class=" + klass);
}
// This constructor passes through to the other constructor
public JythonObjectFactory(Class interfaceType, String moduleName, String className) {
this(new PySystemState(), interfaceType, moduleName, className);
}
// All of the followng methods return
// a coerced Jython object based upon the pieces of information
// that were passed into the factory. The differences are
// between them are the number of arguments that can be passed
// in as arguents to the object.
public Object createObject() {
return klass.__call__().__tojava__(interfaceType);
}
public Object createObject(Object arg1) {
return klass.__call__(Py.java2py(arg1)).__tojava__(interfaceType);
}
public Object createObject(Object arg1, Object arg2) {
return klass.__call__(Py.java2py(arg1),
Py.java2py(arg2)).__tojava__(interfaceType);
}
public Object createObject(Object arg1, Object arg2, Object arg3) {
return klass.__call__(Py.java2py(arg1), Py.java2py(arg2),
Py.java2py(arg3)).__tojava__(interfaceType);
}
public Object createObject(Object args[], String keywords[]) {
PyObject convertedArgs[] = new PyObject[args.length];
for (int i = 0; i < args.length; i++) {
convertedArgs[i] = Py.java2py(args[i]);
}
return klass.__call__(convertedArgs, keywords).__tojava__(interfaceType);
}
public Object createObject(Object... args) {
return createObject(args, Py.NoKeywords);
}
}
Main.java
import org.jython.book.interfaces.BuildingType;
import org.jython.book.util.JythonObjectFactory;
public class Main{
187
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
public static void main(String args[]) {
JythonObjectFactory factory = new JythonObjectFactory(
BuildingType.class, "building", "Building");
BuildingType building = (BuildingType) factory.createObject();
building.setBuildingName("BUIDING-A");
building.setBuildingAddress("100 MAIN ST.");
building.setBuildingId(1);
System.out.println(building.getBuildingId() + " " + building.getBuildingName() + " "
+
building.getBuildingAddress());
}
}
As you can see from the code, there are quite a few differences from the object factory
implementation shown previously. First, you can see that the instantiation of the object factory requires
different arguments. In this case, we pass in the interface, module, and class name. Next, you can see
that the PySystemState obtains a reference to the importer PyObject. The importer then makes a __call__
to the module we’ve requested. The requested module must be contained somewhere on the sys.path.
Lastly, we obtain a reference to our class by calling the __getattr__ method on the module. We can now
use the returned class to perform the coercion of our Jython object into Java. As mentioned previously,
you’ll note that this particular implementation includes several createObject() variations allowing one to
pass arguments to the module when it is being called. This, in effect, gives us the ability to pass
arguments into the initializer of the Jython object.
Which object factory is best? Your choice, depending upon the situation you’re application is
encountering. Bottom line is that there are several ways to perform the object factory design and they all
allow seamless use of Jython objects from within Java code.
Now that we have a coerced Jython object, we can go ahead and utilize the methods that have been
defined in the Java interface. As you can see, the simple example above sets a few values and then prints
out the object values. Hopefully you can see how easy it is to create a single object factory that we can be
use for any Jython object rather than just one.
Returning __doc__ Strings
It is also very easy to obtain the __doc__ string from any of your Jython classes by coding an accessor
method on the object itself. We’ll add some code to the building object that was used in the previous
examples. It doesn’t matter what type of factory you decide to work with, this trick will work with both.
Listing 10-6. __doc__ Strings
Building.py
from org.jython.book.interfaces import BuildingType
# Notice the doc string that has been added after the class definition below
class Building(BuildingType):
''' Class to hold building objects '''
188
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
def __init__(self):
self.name = None
self.address = None
self.id = -1
def getBuildingName(self):
return self.name
def setBuildingName(self, name):
self.name = name;
def getBuildingAddress(self):
return self.address
def setBuildingAddress(self, address):
self.address = address
def getBuildingId(self):
return self.id
def setBuildingId(self, id):
self.id = id
def getDoc(self):
return self.__doc__...
BuildingType.java
package org.jython.book.interfaces;
public interface BuildingType {
public
public
public
public
public
public
public
String getBuildingName();
String getBuildingAddress();
int getBuildingId();
void setBuildingName(String name);
void setBuildingAddress(String address);
void setBuildingId(int id);
String getDoc();
}
Main.java
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
189
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
import org.jython.book.interfaces.BuildingType;
import org.plyjy.factory.JythonObjectFactory;
public class Main {
public static void main(String[] args) {
JythonObjectFactory factory = JythonObjectFactory.getInstance();
BuildingType building = (BuildingType) factory.createObject(
BuildingType.class, "Building");
building.setBuildingName("BUIDING-A");
building.setBuildingAddress("100 MAIN ST.");
building.setBuildingId(1);
System.out.println(building.getBuildingId() + " " + building.getBuildingName() + " "
+
building.getBuildingAddress());
// It is easy to print out the documentation for our Jython object
System.out.println(building.getDoc());
}
}
Result:
1 BUIDING-A 100 MAIN ST.
Class to hold building objects
Applying the Design to Different Object Types
This design will work with all object types, not just plain old Jython objects. In the following example, the
Jython module is a class containing a simple calculator method. The factory coercion works the same
way, and the result is a Jython class that is converted into Java.
Listing 10-7. Different Method Types
CostCalculator.py
from org.jython.book.interfaces import CostCalculatorType
class CostCalculator(CostCalculatorType, object):
''' Cost Calculator Utility '''
def __init__(self):
print 'Initializing'
pass
# The implementation for the definition contained in the Java interface
def calculateCost(self, salePrice, tax):
return salePrice + (salePrice * tax)
CostCalculatorType.java
package org.jython.book.interfaces;
190
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
public interface CostCalculatorType {
public double calculateCost(double salePrice, double tax);
}
Main.java
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jython.book.interfaces.CostCalculatorType;
import org.plyjy.factory.JythonObjectFactory;
public class Main {
public static void main(String[] args) {
// Create factory and coerce Jython calculator object
JythonObjectFactory factory = JythonObjectFactory.getInstance();
CostCalculatorType costCalc = (CostCalculatorType) factory.createObject(
CostCalculatorType.class, "CostCalculator");
System.out.println(costCalc.calculateCost(25.96, .07));
}
}
Result
Initializing
27.7772
A BIT OF HISTORY
Prior to Jython 2.5, the standard distribution of Jython included a utility known as jythonc. Its main purpose
was to provide the ability to convert Python modules into Java classes so that Java applications could
seamlessly make use of Python code, albeit in a roundabout fashion. jythonc actually compiles the Jython
code down into Java .class files and then the classes are utilized within the Java application. This utility
could also be used to freeze code modules, create jar files, and to perform other tasks depending upon
which options were used. This technique is no longer the recommended approach for utilizing Jython
within Java applications. As a matter of fact, jythonc is no longer packaged with the Jython distribution
beginning with the 2.5 release.
In order for jythonc to take a Jython class and turn it into a corresponding Java class, it had to adhere to a
few standards. First, the Jython class had to subclass a Java object, either a class or interface. It also had
to do one of the following: override a Java method, implement a Java method, or create a new method
using a signature.
191
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
While this method worked well and did what it was meant to do, it caused a separation between the
Jython code and the Java code. The step of using jythonc to compile Jython into Java is clean, yet, it
creates a rift in the development process. Code should work seamlessly without the need for separate
compilation procedure. One should have the ability to utilize Jython classes and modules from within a
Java application by reference only, and without a special compiler in between. There have been some
significant advances in this area, and many of the newer techniques have been discussed in this chapter.
JSR-223
With the release of Java SE 6 came a new advantage for dynamic languages on the JVM. JSR-223 enables
dynamic languages to be callable via Java in a seamless manner. Although this method of accessing
Jython code is not quite as flexible as using an object factory, it is quite useful for running short Jython
scripts from within Java code. The scripting project (https://scripting.dev.java.net/) contains many
engines that can be used to run different languages within Java. In order to run the Jython engine, you
must obtain jython-engine.jar from the scripting project and place it into your classpath. You must also
place jython.jar in the classpath, and it does not yet function with Jython 2.5 so Jython 2.5.1 must be
used.
Below is a small example showing the utilization of the scripting engine.
Listing 10-8. Using JSR-223
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws ScriptException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("python");
// Using the eval() method on the engine causes a direct
// interpretataion and execution of the code string passed into it
engine.eval("import sys");
engine.eval("print sys");
// Using the put() method allows one to place values into
// specified variables within the engine
engine.put("a", "42");
// As you can see, once the variable has been set with
// a value by using the put() method, we an issue eval statements
// to use it.
engine.eval("print a");
engine.eval("x = 2 + 2");
// Using the get() method allows one to obtain the value
// of a specified variable from the engine instance
Object x = engine.get("x");
192
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
System.out.println("x: " + x);
}
}
Next, we see the result of running the application. The first two lines are automatically generated
when the Jython interpreter is initiated; they display the JAR filescontained within the CLASSPATH.
Following those lines, we see the actual program output.
Result
*sys-package-mgr*: processing new jar, '/jsr223-engines/jython/build/jython-engine.jar'
*sys-package-mgr*: processing modified jar, '/System/Library/Java/Extensions/QTJava.zip'
sys module
42
x: 4
Utilizing PythonInterpreter
A similar technique to JSR-223 for embedding Jython is making use of the PythonInterpreter directly.
This style of embedding code is very similar to making use of a scripting engine, but it has the advantage
of working with Jython 2.5. Another advantage is that the PythonInterpreter enables you to make use of
PyObjects directly. In order to make use of the PythonInterpreter technique, you only need to have
jython.jar in your classpath; there is no need to have an extra engine involved.
Listing 10-9. Using PythonInterpreter
import
import
import
import
org.python.core.PyException;
org.python.core.PyInteger;
org.python.core.PyObject;
org.python.util.PythonInterpreter;
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws PyException {
// Create an instance of the PythonInterpreter
PythonInterpreter interp = new PythonInterpreter();
// The exec() method executes strings of code
interp.exec("import sys");
interp.exec("print sys");
// Set variable values within the PythonInterpreter instance
interp.set("a", new PyInteger(42));
interp.exec("print a");
interp.exec("x = 2+2");
//
//
Obtain the value of an object from the PythonInterpreter and store it
into a PyObject.
193
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
PyObject x = interp.get("x");
System.out.println("x: " + x);
}
}
In the class above, we make use of the PythonInterpreter to execute Python code within the Java
class. First, we create an instance of the PythonInterpreter object. Next, we make exec() calls against it to
execute strings of code passed into it. Next we use the set() method in order to set variables within the
interpreter instance. Lastly, we obtain a copy of the object that is stored in the variable x within the
interpreter. We must store that object as a PyObject in our Java code.
Results
42
x: 4
The following is a list of methods available for use within a PythonInterpreter object along with a
description of functionality.
Table 10-2. PythonInterpreter Methods
Method
Description
setIn(PyObject)
Set the Python object to use for the standard input stream
setIn(java.io.Reader)
Set a java.io.Reader to use for the standard input stream
setIn(java.io.InputStream)
Set a java.io.InputStream to use for the standard input stream
setOut(PyObject)
Set the Python object to use for the standard output stream
setOut(java.io.Writer)
Set the java.io.Writer to use for the standard output stream
setOut(java,io.OutputStream)
Set the java.io.OutputStream to use for the standard output stream
setErr(PyObject)
Set a Python error object to use for the standard error stream
setErr(java.io.Writer
Set a java.io.Writer to use for the standard error stream
setErr(java.io.OutputStream)
Set a java.io.OutputStream to use for the standard error stream
eval(String)
Evaluate a string as Python source and return the result
eval(PyObject)
Evaluate a Python code object and return the result
exec(String)
Execute a Python source string in the local namespace
194
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
Table 10-2. PythonInterpreter Methods (continued)
Method
Description
exec(PyObject)
Execute a Python code object in the local namespace
execfile(String filename)
Execute a file of Python source in the local namespace
execfile(java.io.InputStream)
Execute an input stream of Python source in the local namespace
compile(String)
Compile a Python source string as an expression or module
compile(script, filename)
Compile a script of Python source as an expression or module
set(String name, Object value)
Set a variable of Object type in the local namespace
set(String name, PyObject
value)
Set a variable of PyObject type in the local namespace
get(String)
Get the value of a variable in the local namespace
get(String name, Class
javaclass
Get the value of a variable in the local namespace. The value will be
returned as an instance of the given Java class.
Summary
Integrating Jython and Java is really at the heart of the Jython language. Using Java within Jython works
just as we as adding other Jython modules; both integrate seamlessly. What makes this nice is that now
we can use the full set of libraries and APIs available to Java from our Jython applications. Having the
ability of using Java within Jython also provides the advantage of writing Java code in the Python syntax.
Utilizing design patterns such as the Jython object factory, we can also harness our Jython code
from within Java applications. Although jythonc is no longer part of the Jython distribution, we can still
effectively use Jython from within Java. There are object factory examples available, as well as projects
such as PlyJy (http://kenai.com/projects/plyjy) that give the ability to use object factories by simply
including a JAR in your Java application.
We learned that there are more ways to use Jython from within Java as well. The Java language
added scripting language support with JSR-223 with the release of Java 6. Using a jython engine, we can
make use of the JSR-223 dialect to sprinkle Jython code into our Java applications. Similarly, the
PythonInterpreter can be used from within Java code to invoke Jython. Also keep an eye on projects such
as Clamp (http://github.com/groves/clamp/tree/master): the Clamp project has the goal to make use of
annotations in order to create Java classes from Jython classes. It will be exciting to see where this
project goes, and it will be documented once the project has been completed.
In the next chapter, you will see how we can use Jython from within integrated development
environments. Specifically, we will take a look at developing Jython with Eclipse and Netbeans. Utilizing
an IDE can greatly increase developer productivity, and also assist in subtleties such as adding modules
and JAR files to the classpath.
195
www.it-ebooks.info
CHAPTER 10 ■ JYTHON AND JAVA INTEGRATION
196
www.it-ebooks.info
C H A P T E R 11
■■■
Using Jython in an IDE
In this chapter, we will discuss developing Jython applications using two of the most popular integrated
development environments, Eclipse and Netbeans. There are many other development environments
available for Python and Jython today; however, these two are perhaps the most popular and contain the
most Jython-specific tools. Eclipse has had a plug-in known as PyDev for a number of years, and this
plug-in provides rich support for developing and maintaining Python and Jython applications alike.
Netbeans began to include Python and Jython support with version 6.5 and later. The Netbeans IDE also
provides rich support for development and maintenance of Python and Jython applications.
Please note that in this chapter we will refer to Python/Jython as Jython. All of the IDE options
discussed are available for both Python and Jython unless otherwise noted. For readability and
consistency sake, we’ll not refer to both Python and Jython throughout this chapter unless there is some
feature that is not available for Python or Jython specifically. Also note that we will call the plug-ins
discussed by their names, so in the case of Netbeans the plug-in is called Netbeans Python Plug-in. This
plug-in works with both Python and Jython in all cases.
Eclipse
Naturally, you will need to have Eclipse installed on your machine to use Jython with it. The latest
available version when this book is being written is Eclipse 3.5 (also known as Eclipse Galileo), and it is
the recommended version to use to follow this section. Versions 3.2, 3.3, and 3.4 will work, too, although
there will be minor user interface differences which may confuse you while following this section.
If you don’t have Eclipse installed on your machine, go to www.eclipse.org/downloads and
download the version for Java developers.
Installing PyDev
Eclipse doesn’t include built-in Jython support. Thus, we will use PyDev, an excellent plug-in which
adds support for the Python language and includes specialized support for Jython. PyDev’s home page is
http://pydev.org, but you won’t need to manually download and install it.
To install the plug-in, start Eclipse and go to Help>Install new Software..., and type
http://pydev.org/updates into the “Work with” input box. Press Enter. After a short moment, you will
see an entry for PyDev in the bigger box below. Just select it, clicking on the checkbox that appears at the
left of PyDev (see Figure 11-1), and then click the Next button.
197
www.it-ebooks.info
CHAPTER 11 ! USING JYTHON IN AN IDE
Figure 11-1. Installing PyDev
After this, just follow the wizard, read the license agreement, and, if you agree with the Eclipse
Public License v1.0, accept it. Then click the Finish button.
Once the plug-in has been installed by Eclipse, you will be asked if you want to restart the IDE to
enable the plug-in. As that is the recommended option, do so. Once Eclipse restarts itself, you will enjoy
full Python support on the IDE.
Minimal Configuration
Before starting a PyDev project you must tell PyDev which Python interpreters are available. In this
context, an interpreter is just a particular installation of some implementation of Python. When starting
you will normally only need one interpreter, and for this chapter we will only use Jython 2.5.1. To
configure it, open the Eclipse Preferences dialog (via Windows>Preferences in the main menu bar). On
the text box located at the top of the left panel (called “Filter text”), type “Jython.” This will filter the
myriad of Eclipse (and PyDev!) options and will present us with a much simplified view, in which you
will spot the “Interpreter – Jython” section on the left.
Once you have selected the “Interpreter – Jython” section, you will be presented with an empty list
of Jython interpreters at the top of the right side. We clearly need to fix that! So, click the New button,
enter “Jython 2.5.1” as the Interpreter Name, click Browse, and find jython.jar inside your Jython 2.5.1
installation.
198
www.it-ebooks.info
CHAPTER 11 ! USING JYTHON IN AN IDE
! Note Even if this is the only runtime we will use in this chapter, we recommend you use a naming schema like
the one proposed here, including both the implementation name (Jython) and the full version (2.5.1) on the
interpreter name. This will avoid confusion and name clashing when adding new interpreters in the future.
After selecting the jython.jar file, PyDev will automatically detect the default, global sys.path
entries. PyDev always infer the right values, so unless you have very special needs, just accept the default
selection and click OK.
If all has gone well, you will now see an entry on the list of Jython interpreters, representing the
information you just entered. It will be similar to Figure 11-2 (of course, your filesystem paths will differ).
Figure 11-2. List of Jython interpreters
199
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
That’s all. Click OK and you will be ready to develop with Jython while enjoying the support
provided by a modern IDE.
If you are curious, you may want to explore the other options found on the Preferences window,
below the PyDev section (after clearing the search filter we used to quickly go to the Jython interpreter
configuration). But in our experience, it’s rarely needed to change most of the other options available.
In the next sections we will take a look to the more important PyDev features to have a more
pleasant learning experience and make you more productive.
Hello PyDev!: Creating Projects and Executing Modules
Once you see the first piece of example code on this chapter, it may seem overly simplistic. It is, indeed,
a very dumb example. The point is to keep the focus on the basic steps you will perform for the lifecycle
of any Python-based project inside the Eclipse IDE, which will apply to simple and complex projects. So,
as you probably guessed, our first project will be a Hello World. Let’s start it!
Go to File>New >Project. You will be presented with a potentially long list of all the kinds of projects
you can create with Eclipse. Select PyDev Project under the PyDev group (you can also use the filter text
box at the top and type “PyDev Project” if it’s faster for you).
The next dialog will ask you for your project properties. As the project name, we will use
LearningPyDev. In the “Project contents” field, check the “Use default” checkbox, so PyDev will create a
directory with the same name as the project inside the Eclipse workspace (which is the root path of your
eclipse projects). Because we are using Jython 2.5.1, we will change the project type to Jython and the
grammar version to 2.5. We will leave the Interpreter alone, which will default to the Jython interpreter
we just defined on the Minimal Configuration section. We will also leave checked the “Create default
‘src’ folder and add it to the pythonpath” option, because it’s a common convention on Eclipse projects.
After you click Finish, PyDev will create your project, which will only contain an empty src directory
and a reference to the interpreter being used. Let’s create our program now.
Right-click on the project, and select New>PyDev Module. Leave the Package blank and enter
“main” in the Name field. PyDev offers some templates to speed up the creation of new modules, but we
won’t use them, as our needs are rather humble. So leave the Template field empty and click Finish.
PyDev will present you an editor for the main.py file it just created. It’s time to implement our
program. Write the following code in the editor:
Listing 11-1.
if __name__ == "__main__":
print "Hello PyDev!"
and then press Ctrl + F11 to run this program. Select Jython Run from the dialog presented and click
OK. The program will run and the text “Hello PyDev!” will appear on the console, located on the bottom
area of the IDE.
■ Note When describing the hotkeys (such as Ctrl + F11 for “Jython Run”), we’re using the PC keyboard
convention. Mac users should press the Command key instead of Ctrl for all the hotkeys listed on this chapter,
unless otherwise noted.
If you manually typed the program, you probably noted that the IDE knows that in Python a line
ending in “:” marks the start of a block and will automatically put your cursor at the appropriate level of
200
www.it-ebooks.info
CHAPTER 11 ! USING JYTHON IN AN IDE
indentation in the next line. See what happens if you manually override this decision and put the print
statement at the same indentation level of the if statement and save the file. The IDE will highlight the
line flagging the error. If you hover at the error mark, you will see the explanation of the error, as seen in
Figure 11-3.
Figure 11-3. Error explanation appears when you hover over the error mark.
Expect the same kind of feedback for whatever syntax error you made. It helps to avoid the
frustration of going on edit-run loops only to find further minor syntax errors.
Passing Command-line Arguments and Customizing Execution
Command line arguments may seem old fashioned, but they are actually a very simple and effective way
to let programs interact with the outside. Because you have learned to use Jython as a scripting
language, it won’t be uncommon to write scripts that will take their input from the command line (note
that for unattended execution, reading input from the command line is way more convenient that
obtaining data from the standard input, let alone using a GUI).
As you have probably guessed, we will make our toy program to take a command line argument. The
argument will represent the name of the user to greet, to build a more personalized solution. Here is how
our main.py should look:
Listing 11-2.
import sys
if __name__ = "__main__":
if len(sys.argv) < 2:
print "Sorry, I can't greet you if you don't say your name"
else:
print "Hello %s!" % sys.argv[1]
If you hit Ctrl + F11 again, you will see the “Sorry I can’t greet you...” message on the console. It
makes sense, because you didn’t pass the name. Not to say that it was your fault, as you didn't have a
chance to say your name.
To specify command line arguments, go to the Run>Run Configurations menu, and you will find an
entry named “LearningPyDev main.py” in the Jython Run section on the left. It will probably be already
selected, but if it’s not, select it manually. Then, on the main section of the dialog, you will find ways to
customize the execution of our script. You can change aspects such as the current directory, pass special
argument to the JVM, change the interpreter to use, set environment variables, and so on. We just need
to specify an argument, so let’s type “Bob” in the “Program arguments” box and click Run.
201
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
As you’d expect, the program now prints “Hello Bob!” on the console. Note that the value you
entered is remembered; that is, if you press Ctrl + F11 now, the program will print “Hello Bob!” again.
Some people may point out that this behavior makes testing this kind of program very awkward, because
the Run Configurations dialog will have to be opened each time the arguments need to be changed. But
if we really want to test our programs (which is a good idea), we should do it in the right way. We will
look into that soon, but first let’s finish our tour on basic IDE features.
Playing with the Editor
Let’s extend our example code a bit more, providing different ways to greet our users, in different
languages. We will use the optparse module to process the arguments this time. Refer to Chapter 9 if you
want to remember how to use optparse. We will also use decorators (seen in Chapter 4) to make it trivial
to extend our program with new ways to greet our users. So, our little main.py has grown a bit now.
Listing 11-3.
# -*- coding: utf-8 -*import sys
from optparse import OptionParser
greetings = dict(en=u'Hello %s!',
es=u'Hola %s!',
fr=u'Bonjour %s!',
pt=u'Alò %s!')
uis = {}
def register_ui(ui_name):
def decorator(f):
uis[ui_name] = f
return f
return decorator
def message(ui, msg):
if ui in uis:
uis[ui](msg)
else:
raise ValueError("No greeter named %s" % ui)
def list_uis():
return uis.keys()
@register_ui('console')
def print_message(msg):
print msg
@register_ui('window')
def show_message_as_window(msg):
from javax.swing import JFrame, JLabel
frame = JFrame(msg,
defaultCloseOperation=JFrame.EXIT_ON_CLOSE,
size=(100, 100),
visible=True)
202
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
frame.contentPane.add(JLabel(msg))
if __name__ == "__main__":
parser = OptionParser()
parser.add_option('--ui', dest='ui', default='console',
help="Sets the UI to use to greet the user. One of: %s" %
", ".join("'%s'" % ui for ui in list_uis()))
parser.add_option('--lang', dest='lang', default='en',
help="Sets the language to use")
options, args = parser.parse_args(sys.argv)
if len(args) < 2:
print "Sorry, I can't greet you if you don't say your name"
sys.exit(1)
if options.lang not in greetings:
print "Sorry, I don't speak '%s'" % options.lang
sys.exit(1)
msg = greetings[options.lang] % args[1]
try:
message(options.ui, msg)
except ValueError, e:
print "Invalid UI name\n"
print "Valid UIs:\n\n" + "\n".join(' * ' + ui for ui in list_uis())
sys.exit(1)
Take a little time to play with this code in the editor. Try pressing Ctrl + Space (don’t change Ctrl
with Command if you are using Mac OS X; this hotkey is the same on every platform), which is the
shortcut for automatic code completion (also known as Intellisense in Microsoft’s parlance) on different
locations. It will provide completion for import statements (try completing that line just after the
import token, or in the middle of the OptionParser token) and attribute or method access (like on
sys.exit or parser.add_option or even in JFrame.EXIT_ON_CLOSE which is accessing a Java class!) It
also provides hints about the parameters in the case of methods.
In general, every time you type a dot, the automatic completion list will pop up, if the IDE knows
enough about the symbol you just typed to provide help. But you can also call for help at any point. For
example, go to the bottom of the code and type “message(.” Suppose you just forgot the order of the
parameters to that function. Solution: Press Ctrl + Space and PyDev will complete the statement, using
the name of the formal parameters of the function.
Also try Ctrl + Space on keywords like “def.” PyDev will provide you little templates that may save
you some typing. You can customize the templates on the PyDev>Editor>Templates section of the
Eclipse Preferences window (available on the Window>Preferences main menu).
The other thing you may have noted now that we have a more sizable program with some imports,
functions, and global variables is that the Outline panel on the right side of the IDE window shows a
tree-structure view of code being edited showing such features. It also displays classes, by the way.
And don’t forget to run the code! Of course, it’s not really spectacular to see that after pressing Ctrl
+ F11 we still get the same boring “Hello Bob!” text on the console. But if you edit the command line
argument (via the Run Configurations dialog) to the following: “Bob --lang es --ui window,” you will
get a nice window greeting Bob in Spanish. Also see what happens if you specify a non supported UI
(say, --ui speech) or an unsupported language. We even support the --help! So we have a generic,
polyglot greeter which also happens to be reasonably robust and user friendly (for command line
program standards that is).
203
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
At this point you are probably tired of manually testing the program editing the command line
argument on that dialog. Just one more section and we will see a better way to test our program using
the IDE. Actually, part of the next section will help us move toward the solution.
A Bit of Structure: Packages, Modules, and Navigation
If you like simplicity you may be asking (or swearing, depending on your character) why we overengineered the last example. There are simpler (in the sense of a more concise and understandable
code) solutions to the same problem statement. But we needed to grow the toy code to explore another
aspect of IDEs, which for some people are a big reason to use them: organizing complex code bases. And
you don’t expect me to put a full-blown Pet Store example in this book to get to that point, do you?
So, let’s suppose that the complications we introduced (mainly the registry of UIs exposed via
decorators) are perfectly justified, because we are working on a slightly complicated problem. In other
words: let’s extrapolate.
The point is, we know that the great majority of our projects can’t be confined to just one file (one
Python module). Even our very dumb example is starting to get unpleasant to read. And, when we realize
that we need more than one module, we also realize we need to group our modules under a common
umbrella, to keep it clear that our modules form a coherent thing together and to lower the chances of
name clashing with other projects. So, as seen in Chapter 8, the Python solution to this problem is
modules and packages.
Our plan is to organize the code as follows: everything will go under the package “hello.” The core
logic, including the language support, will go into the package itself (into its __init__.py file) and each
UI will go into its own module under the “hello” package. The main.py script will remain as the
command line entry point.
Right-click on the project and select New>PyDev Package. Enter “hello” as the Name and click
Finish. PyDev will create the package and open an editor for its __init.py__ file. As we said, we will move
the core logic to this package, so this file will contain the following code, extracted from our previous
version of the main code:
Listing 11-4.
# -*- coding: utf-8 -*greetings = dict(en=u'Hello %s!',
es=u'Hola %s!',
fr=u'Bonjour %s!',
pt=u'Alò %s!')
class LanguageNotSupportedException(ValueError):
pass
class UINotSupportedExeption(ValueError):
pass
uis = {}
def register_ui(ui_name):
def decorator(f):
uis[ui_name] = f
return f
return decorator
def message(ui, msg):
'''
204
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Displays the message `msg` via the specified UI which has to be
previously registered.
'''
if ui in uis:
uis[ui](msg)
else:
raise UINotSupportedExeption(ui)
def list_uis():
return uis.keys()
def greet(name, lang, ui):
'''
Greets the person called `name` using the language `lang` via the
specified UI which has to be previously registered.
'''
if lang not in greetings:
raise LanguageNotSupportedException(lang)
message(ui, greetings[lang] % name)
Note that we embraced the idea of modularizing our code, providing exceptions to notify clients of
problems when calling the greeter, instead of directly printing messages on the standard output.
Now we will create the hello.console module containing the console UI. Right-click on the project,
select New>PyDev Module, Enter “hello” as the Package and “console” as the Name. You can avoid
typing the package name if you right-click on the package instead of the project. Click Finish and copy
the print_message function there:
Listing 11-5.
from hello import register_ui
@register_ui('console')
def print_message(msg):
print msg
Likewise, create the window module inside the hello package, and put there the code for
show_message_as_window:
Listing 11-6.
from javax.swing import JFrame, JLabel
from hello import register_ui
@register_ui('window')
def show_message_as_window(msg):
frame = JFrame(msg,
defaultCloseOperation=JFrame.EXIT_ON_CLOSE,
size=(100, 100),
visible=True)
frame.contentPane.add(JLabel(msg))
Finally, the code for our old main.py is slightly reshaped into the following:
205
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Listing 11-7.
import sys
import hello, hello.console, hello.window
from optparse import OptionParser
def main(args):
parser = OptionParser()
parser.add_option('--ui', dest='ui', default='console',
help="Sets the UI to use to greet the user. One of: %s" %
", ".join("'%s'" % ui for ui in list_uis()))
parser.add_option('--lang', dest='lang', default='en',
help="Sets the language to use")
options, args = parser.parse_args(args)
if len(args) < 2:
print "Sorry, I can't greet you if you don't say your name"
return 1
try:
hello.greet(args[1], options.lang, options.ui)
except hello.LanguageNotSupportedException:
print "Sorry, I don't speak '%s'" % options.lang
return 1
except hello.UINotSupportedExeption:
print "Invalid UI name\n"
print "Valid UIs:\n\n" + "\n".join(' * ' + ui for ui in hello.list_uis())
return 1
return 0
if __name__ == "__main__":
main(sys.argv)
■ Tip Until now, we have used PyDev's wizards to create new modules and packages. But, as you saw in Chapter
8, modules are just files with the .py extension located on the sys.path or inside packages, and packages are
just directories that happen to contain a __init__.py file. So you may want to create modules using New>File
and packages using New>Folder if you don't like the wizards.
Now we have our code split over many files. On a small project, navigating through it using the leftside project tree (called the PyDev Package Explorer) isn’t difficult, but you can imagine that on a project
with dozens of files it would be. So we will see some ways to ease the navigation of a code base.
First, let’s suppose you are reading main.py and want to jump to the definition of the hello.greet
function, called on line 17. Instead of manually changing to such a file and scanning until finding the
function, just press Ctrl and click greet. PyDev will automatically move you into the definition. This also
works on most variables and modules (try it on the import statements, for example).
Another good way to quickly jump between files without having to resort to the Package Explorer is
to use Ctrl + Shift + R, which is the shortcut for "Open Resource". Just type (part of) the file name you
want to jump to and PyDev will search on every package and directory of your open projects.
206
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Now that you have many files, note that you don't need to necessarily have the file you want to run
opened and active on the editor. For every script you run (using the procedure in which you need to be
editing the program and then press Ctrl + F11) the IDE will remember that such script is something you
are interested in running and will add it to the "Run History". You can access the "Run History" on the
main menu under Run -> Run History, or in the dropdown button located in the main toolbar, along the
green "play" icon. In both places you will find the latest programs you ran, and many times using this list
and selecting the script you want to re-run will be more convenient than jumping to the script on the
editor and then pressing Ctrl + F11.
Finally, the IDE internally records a history of your "jumps" between files, just like a web browser do
for web pages you visit. And just like a web browser you can go back and forward. To do this, use the
appropriate button on the toolbar or the default shortcuts which are Ctrl + Left and Ctrl + Right.
Testing
Okay, it’s about time to explore our options to test our code, without resorting to the cumbersome
manual black box testing we have been doing changing the command line argument and observing the
output.
PyDev supports running PyUnit tests from the IDE, so we will write them. Let’s create a module
named tests on the hello package with the following code:
Listing 11-8.
import unittest
import hello
class UIMock(object):
def __init__(self):
self.msgs = []
def __call__(self, msg):
self.msgs.append(msg)
class TestUIs(unittest.TestCase):
def setUp(self):
global hello
hello = reload(hello)
self.foo = UIMock()
self.bar = UIMock()
hello.register_ui('foo')(self.foo)
hello.register_ui('bar')(self.bar)
hello.message('foo', "message using the foo UI")
hello.message('foo', "another message using foo")
hello.message('bar', "message using the bar UI")
def testBarMessages(self):
self.assertEqual(["message using the bar UI"], self.bar.msgs)
def testFooMessages(self):
self.assertEqual(["message using the foo UI",
"another message using foo"],
self.foo.msgs)
def testNonExistentUI(self):
self.assertRaises(hello.UINotSupportedExeption,
207
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
hello.message, 'non-existent-ui', 'msg')
def testListUIs(self):
uis = hello.list_uis()
self.assertEqual(2, len(uis))
self.assert_('foo' in uis)
self.assert_('bar' in uis)
As you can see, the test covers the functionality of the dispatching of messages to different UIs. A
nice feature of PyDev is the automatic discovery of tests, so you don’t need to code anything else to run
the previous tests. Just right-click on the src folder on the Package Explorer and select Run As>Jython
unit-test. You will see the output of the test almost immediately on the console:
Listing 11-9.
Finding files...
['/home/lsoto/eclipse3.5/workspace-jythonbook/LearningPyDev/src/'] ... done
Importing test modules ... done.
testBarMessages (hello.tests.TestUIs) ... ok
testFooMessages (hello.tests.TestUIs) ... ok
testListUIs (hello.tests.TestUIs) ... ok
testNonExistentUI (hello.tests.TestUIs) ... ok
---------------------------------------------------------------------Ran 4 tests in 0.064s
OK
Python’s unittest is not the only testing option on the Python world. A convenient way to do tests
which are more black-box-like than unit test, though equally automated is doctest.
■ Note We will cover testing tools in much greater detail in Chapter 18, so take a look at that chapter if you feel
too disoriented.
The nice thing about doctests is that they look like an interactive session with the interpreter, which
makes them quite legible and easy to create. We will test our console module using a doctest.
First, click the right-most button on the console’s toolbar (you will recognize it as the one with a
plus sign on its upper left-hand corner, which has the Open Console tip when you pass the mouse over
it). From the menu, select PyDev Console. To the next dialog, answer Jython Console. After doing this
you will get an interactive interpreter embedded on the IDE.
Let’s start exploring our own code using the interpreter:
208
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Listing 11-10.
>>> from hello import console
>>> console.print_message("testing")
testing
We highly encourage you to type those two commands yourself. You will note how code completion
also works on the interactive interpreter!
Back to the topic, we just interactively checked that our console module works as expected. The cool
thing is that we can copy and paste this very snippet as a doctest that will serve to automatically check
that the behavior we just tested will stay the same in the future.
Create a module named doctests inside the “hello” package and paste those three lines from the
interactive console, surrounding them by triple quotes (because they are not syntactically correct
Python code after all). After adding a little of boilerplate to make this file executable, it will look like this:
Listing 11-11.
"""
>>> from hello import console
>>> console.print_message("testing")
testing
"""
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
After doing this, you can run this test via the Run>Jython run menu while doctests.py is the
currently active file on the editor. If all goes well, you will get the following output:
Listing 11-12.
Trying:
from hello import console
Expecting nothing
ok
Trying:
console.print_message("testing")
Expecting:
testing
ok
1 items passed all tests:
2 tests in __main__
2 tests in 1 items.
2 passed and 0 failed.
Test passed.
After running the doctest you will notice that your interactive console has gone away, replaced by
the output console showing the test results. To go back to the interactive console, look for the console
button in the console tab toolbar, exactly at the left of the button you used to spawn the console. Then
on the drop-down menu select the PyDev Console, as shown in Figure 11-4.
209
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Figure 11-4. Selecting PyDev Console
As you can see, you can use the interactive console to play with your code, try ideas, and test them.
And later a simple test can be made just by copying and pasting text from the same interactive console
session. Of special interest is the fact that, because Jython code can access Java APIs quite easily, you can
also test classes written with Java in this way.
Adding Java Libraries to the Project
Finally, we will show you how to integrate Java libraries into your project. We said some pages ago that
we could add a “speech” interface for our greeter. It doesn’t sound like a bad idea after all, because (like
with almost any aspect) the Java world has good libraries to solve that problem.
We will use the FreeTTS library, which can be downloaded from
http://freetts.sourceforge.net/docs/index.php. (You should download the binary version.)
After downloading FreeTTS, you will have to extract the archive on some place on your hard disk.
Then, we will import a JAR file from FreeTTS into our PyDev project.
Right-click the project and select Import. Then choose General>File System and browse to the
directory in which you expanded FreeTTS and select it. Finally, expand the directory on the left side
panel and check the lib subdirectory. See Figure 11-5.
Figure 11-5. Adding Java libraries to the project
210
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
After clicking Finish, you will see that the files are now part of your project.
■ Tip Alternatively, and depending on your operating system, the same operation can be performed copying the
files or folders from the file manager and pasting it into the project (either via menu, keyboard shortcuts, or drag
and drop).
Now, the files are part of the project, but we need to tell PyDev that lib/freetts.jar is a JAR file and
should be added to the sys.path of our project environment. To do this, right-click on the project and
select Properties. Then, on the left panel of the dialog, select PyDev - PYTHONPATH. Then click the “Add
zip/jar/egg” button and select the lib/freetts.jar file on the right side of the dialog that will appear.
Click OK on both dialogs and you are ready to use this library from Python code.
The code for our new hello.speech module is as follows:
Listing 11-13.
from com.sun.speech.freetts import VoiceManager
from hello import register_ui
@register_ui('speech')
def speech_message(msg):
voice = VoiceManager().getVoice("kevin16")
voice.allocate()
voice.speak(msg)
voice.deallocate()
If you play with the code on the editor you will notice that PyDev also provides completion for
imports statement referencing the Java library we are using.
Finally, we will change the second line of main.py from:
Listing 11-14.
import hello, hello.console, hello.window
to
import hello, hello.console, hello.window, hello.speech
in order to load the speech UI too. Feel free to power on the speakers and use the --ui speech option to
let the computer greet yourself and your friends!
There you go, our humble greeter has finally evolved into a quite interesting, portable program with
speech synthesis abilities. It’s still a toy, but one which shows how quickly you can move with the power
of Jython, the diversity of Java, and the help of an IDE.
Debugging
PyDev also offers full debugging capabilities for your Jython code. To try it just put some breakpoints in
your code by double-clicking on the left margin of the editor, and then start your program using the F11
shortcut instead of Ctrl + F11.
211
www.it-ebooks.info
CHAPTER 11 ! USING JYTHON IN AN IDE
Once the debugger hits your breakpoint, the IDE will ask you to change its perspective. This means
it will change to a different layout, better suited for debugging activities. Answer Yes and you will find
yourself on the debugging perspective, shown in Figure 11-6.
Figure 11-6. Debugging perspective
The perspective offers the typical elements of a debugger. In the upper left area in the contents of
the “Debug” tab we have the call stack for each running thread. Click on an item of the call to navigate to
the particular line of code which made the corresponding call. The call stack view also has influence over
what is shown by the Variables panel on the upper right-hand area, which lists all the current local and
global variables. You can “drill down” on every non-primitive value to see its components, as a tree. By
default the variables shown are from the point of view of the code being currently executed. But if we
select a different element on the call stack in the left area it will show the variables for the line of code
associated with that particular stack frame.
Also in the same upper right-hand area there is the Breakpoints tab, which is quite useful for taking
a global look at all the breakpoints defined. Clicking on the breakpoint entry will navigate the code editor
to the associated line of code, of course. And you can disable, enable, and remove breakpoints by rightclicking on the entries.
The rest of the elements are already known: the central area is filled by the main editor (using less
space this time to make room for the extra tools) and its outline, while the output console takes the lower
area.
212
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Once you reach a breakpoint you can control the execution, by using Step Into (F5) to go into the
code of the next function call, Step Over (F6) to run the current line and stop again, Step Return (F7) to
execute the remaining code of the current function, and Resume Execution (F8) to let the program
continue running until the next breakpoint is reached (or the program finishes).
Once you finish your debugging session, you can go back to the normal editing perspective by
selecting PyDev on the upper right-hand area of the main IDE Window (which will have the Debug
button pushed while staying in the debugging perspective).
Conclusion about Eclipse
PyDev is a very mature plug-in for the Eclipse platform, which can be an important element in your
toolbox. Automatic completion and suggestions help a lot when learning new APIs (both Python APIs
and Java APIs!) especially if paired with the interactive console. It is also a good way to introduce a whole
team into Jython or into a specific Jython project, because the project-level configuration can be shared
via normal source control systems. Not to mention that programmers coming from the Java world will
find themselves much more comfortable on a familiar environment.
To us, IDEs are a useful part of our toolbox, and tend to shine on big codebases and/or complex
code which we may not completely understand yet. Powerful navigation and refactoring abilities are key
to the process of understanding such projects and are features that should only improve in the future.
Even if the refactoring capabilities are not still as complete as the state of the art on Java IDEs, we
encourage you to try them on PyDev: “Extract local variable,” “Inline local variable,” and “Extract
method” are quite useful. Even if the alternative of doing the refactor manually isn't as painful with
Python as with Java (or any other statically typed language without type inference), when the IDE can do
the right thing for you and avoid some mechanical work, you will be more productive.
Finally, the debugging capabilities of PyDev are superb and will end your days of using print as a
poor man’s debugger (seriously, we did that for a while!) Even more advanced Python users who master
the art of import pdb; pdb.set_trace() should give it a try.
Now, PyDev isn’t the only IDE available for Jython. If you are already using the Netbeans IDE or
didn’t like Eclipse or PyDev for some reason, take a look at the rest of this chapter, in which we will cover
the Netbeans plug-in for Python development.
Netbeans
The Netbeans integrated development environment has been serving the Java community well for over
ten years now. During that time, the tool has matured quite a bit from what began as an ordinary Java
development tool into what is today an advanced development and testing environment for Java and
other languages alike. As Java and JavaEE application development still remain an integral part of the
tool, other languages such as JRuby, Python, Groovy, and Scala have earned themselves a niche in the
tool as well. Most of these languages are supported as plug-ins to the core development environment,
which is what makes Netbeans such an easy IDE to extend, as it is very easy to build additional features
to distribute. The Python support within Netbeans began as a small plug-in known as nbPython, but it
has grown into a fully featured Python development environment and it continues to grow.
The Netbeans Python support provides developers with all of the expected IDE features, such as
code completion, color-coding, and easy runtime development. It also includes some nice advanced
features for debugging applications and the like.
IDE Installation and Configuration
The first step for installing the Netbeans Python development environment is to download the current
release of the Netbeans IDE. At the time of this writing, Netbeans 6.7.1 is the most recent release, but 6.8
is right around the corner. You can find the IDE download by going to the web site www.netbeans.org
213
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
and clicking on the download link. Once you do so, you’ll be presented with plenty of different download
options. These are variations of the IDE that are focused on providing different features for developers
depending upon what they will use the most. Nobody wants a bulky, memory-hungry development tool
that will overhaul a computer to the extreme. By providing several different configurations of the IDE,
Netbeans gives you the option to leave off the extras and only install those pieces that are essential to
your development. The different flavors for the IDE include Java SE, Java, Ruby, C/C++, PHP, and All. For
those developers only interested in developing core Java applications, the Java SE download would
suffice. Likewise, someone interested in any of the other languages could download the IDE
configuration specific to that language. For the purposes of this book and in our everyday development,
we use the All option, because as we enjoy having all of the options available. However, there are options
available for adding features if you download only the Java SE or another low-profile build and wish to
add more later.
At the time of this writing, there is also a link near the top of the downloads page for PythonEA
distribution. If that link or a similar Python Netbeans distribution link is available, then you can use it to
download and install just the Jython-specific features of the Netbeans IDE. We definitely do not
recommend taking this approach unless you plan to purely code Python applications alone. It seems to
us that a large population of the Jython developer community also codes some Java, and may even
integrate Java and Jython within their applications. If this is the case, you will want to have the Javaspecific features of Netbeans available as well. That is why we do not recommend the Python-only
distribution for Jython developers, but the choice is there for you to make.
Now that you’ve obtained the IDE, it is important to take a look at the license. Python support for
Netbeans is licensed under CDDL version 1.0, so it may be a good idea to take a look at that as well. It is
easy to install in any environment using the intuitive Netbeans installer. Perhaps the most daunting task
when using a new IDE is configuring it for your needs. This should not be the case with Netbeans though
because the configuration for Java and Python alike are quite simple. For instance, if you working with
the fully-featured installation, you will already have application servers available for use as Netbeans
installs Glassfish by default. Note that it is a smart idea to change that admin password very soon after
installation in order to avoid any potentially embarrassing security issues.
When the IDE initially opens up, you are presented with a main window that includes links to blogs
and articles pertaining to Netbeans features. You also have the standard menu items available such as
File, Edit, Tools, and so on. In this chapter we will specifically cover the configuration and use of the
Jython features; however, there are very useful tutorials available online and in book format for covering
other Netbeans features. One thing you should note at this point is that with the initial installation,
Python/Jython development tools are not yet installed unless you chose to install the PythonEA
distribution. Assuming that you have installed the full Netbeans distribution, you will need to add the
Python plug-in via the Netbeans plug-in center. You will need to go to the Tools menu and then open the
Plug-ins submenu. From there, you should choose the Available Plug-ins tab and sort by category. Select
all of the plug-ins in the Python category and then install. This option will install the Python plug-in as
well as a distribution of Jython. You will need to follow on-screen directions to complete the installation.
Once the plug-in has been successfully installed then it is time to configure your Python and Jython
homes. To do so, go to the Tools menu and then open the Python Platforms menu as this will open the
platform manager for Python/Jython. At the time of this writing, the default Jython version that was
installed with the Python plug-in was 2.5+. You most likely have your own Jython installation by now
that includes additional packages that you may wish to use. As this is the case, go ahead and add your
Jython installation as a platform option and make it the default (see Figure 11-7).
214
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Figure 11-7. Adding your Jython installation as a platform option and making it the default
To do so, click on the New button underneath the platform listing. You can try to select the Auto
Detect option, but we did not have luck with Netbeans finding our Jython installation using it. If you
choose the New button, then you will be presented with a file chooser window. You should choose the
Jython executable that resides in the area /bin and all of the other necessary fields
will auto-populate with the correct values. Once completed, choose the Close button near the bottom of
the Python Platform Manager window. You are now ready to start programming with Python and Jython
in Netbeans.
Advanced Python Options
If you enter the Netbeans preferences window you will find some more advanced options for
customizing your Python plug-in. If you go to the Editor tab, you can set up Python specific options for
formatting, code templates, and hints. In doing so, you can completely customize the way that Netbeans
displays code and offers assistance when working with Jython. You can also choose to set up different
fonts and coloring for Python code by selecting the Fonts and Colors tab. This is one example of just how
customizable Netbeans really is because you can set up different fonts and colors for each language type.
If you choose the Miscellaneous tab you can add different file types to the Netbeans IDE and
associate them with different IDE features. If you look through the pull-down menu of files, you can see
that files with the extension of py or pyc are associated as Python files. This ensures that files with the
associated extensions will make use of their designated Netbeans features. For instance, if we wanted to
designate a different extension on some Jython-related files, we could easily do so and associate this
extension with Python files in Netbeans. Of course, we do not recommend doing so, as Jython will not
import files with unknown extensions! Once we’ve made this association then we can create files with an
extension of that we've added and use them within Netbeans just as if they were Python files. Lastly, you
can alter a few basic options such as enabling prompting for python program arguments, and changing
debugger port and shell colors from the Python tab in Netbeans preferences.
215
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
General Python Usage
As stated previously in the chapter, there are a number of options when using the Netbeans Python
solution. There are a few different selections that can be made when creating a new Python project. You
can either choose to create a Python Project or Python Project with Existing Sources. These two project
types are named quite appropriately, as a Python Project will create an empty project; once created it is
easy to develop and maintain applications and scripts alike. Moreover, you can debug your application
via the Python debugger as derived from Jean-Yves Mengant’s jpydbg debugger, and have Netbeans
create tests if you choose to do so. One of the first nice features you will notice right away is the syntax
coloring in the editor.
Standalone Jython Apps
In this section, we will discuss how to develop a standalone Jython application within Netbeans. We will
use a variation of the standard HockeyRoster application that we have used in other places throughout
the book. Overall, the development of a stand-alone Jython application in Netbeans differs very little
from a stand-alone Java application. The main difference is that you will have different project
properties and other options available that pertain to creating Jython projects. And obviously you will be
developing in Jython source files along with all of the color-coding and code completion, and other
options that the Python plug-in has to offer.
To get started, go ahead and create a new Python Project by using the File menu or the shortcut in
the Netbeans toolbar. For the purposes of this section, name the new project HockeyRoster. Uncheck
the option to Create Main File, as we will do this manually. Once your project has been created, explore
some of the options you have available by right-clicking (Ctrl-click) on the project name. The resulting
menu should allow you the option to create new files, run, debug, or test your application, build eggs,
work with code coverage, and more. At this point you can also change the view of your Python packages
within Netbeans by choosing the “View Python Packages as” option. This will allow you the option to
either see the application in list or tree mode, your preference. You can search through your code using
the Find option, share it on Kenai with the integrated Netbeans Kenai support, look at the local file
history, or use your code with a version control system.
■ Note In case you are not familiar with project Kenai, it is an online service started by Sun Microsystems for
hosting open source projects and code. For more information, go to www.kenai.com and check it out.
Click on the Properties option and the Project Properties window should appear. From within the
Project Properties window, there are options listed on the left-hand side including Source, Python, Run,
and Formatting. The Source option provides the ability to change source location or add new source
locations to your project. The Test Root Folders section within this option allows you to add a location
where Python tests reside so that you can use them with your project. The Python option allows you to
change your Python platform and add locations, JARs, and files to your Python path. Changing your
Python platform provides a handy ability to test your program on Jython and Python alike, if you want to
ensure that your code works on each platform. The Run option provides the ability to add or change the
Main module, and add application arguments. Lastly, the Formatting option allows you to specify
different formatting options in Netbeans for this particular project. This is great, because each different
project can have different colored text, and so on, depending upon the options chosen.
At this point, create the Main module for the HockeyRoster application. Go to File>New and rightclicking (Cntrl-click) on the project, or use the toolbar icon. From here you can either create an
216
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Executable Module, Module, Empty Module, Python Package, or Unit Test. Choose to create an
Executable Module and name the main file HockeyRoster.py, and keep in mind that when we created
the project we had the ability to have the IDE generate this file for us but we chose to decline. Personally,
we like to organize our projects using the Python packaging system. Create some packages now using
the same process that you used to create a file and name the package jythonbook. Once created, drag
your HockeyRoster.py module into the jythonbook package to move it into place. Note that you can also
create several packages at the same time by naming a package like jythonbook.features or something of
the like, which will create both of the resulting packages.
The HockeyRoster main module will be the implementation module for our application, but we still
need somewhere to store each of the player’s information. For this, we will create a module named
Player. Go ahead and create an Empty Module named Player within the same jythonbook package. Now
we will code the Player class for our project. To do so, erase the code that was auto-generated by
Netbeans in the Player.py module and type the following. Note that you can change the default code that
is created when generating a new file by changing the template for Python applications.
Listing 11-15.
# Player.py
# Container to hold player information
class Player:
def __init__(self, id, first, last, position):
self.id = id
self.first = first
self.last = last
self.position = position
def add_assist(self):
self.assists = assists + 1
The first thing to note is that Netbeans will maintain your indentation level. It is also easy to
decrease the indentation level by using the SHIFT + TAB keyboard shortcut. Using the default
environment settings, the keywords should be in a different color (blue by default) than the other code.
Method names will be in bold, and references to self or variables will be in a different color as well. You
should notice some code completion, mainly the automatic self placement after you type a method
name and then the right parentheses. Other subtle code completion features also help to make our
development lives easier. If you make an error, indentation or otherwise, you will see a red underline
near the error, and a red error badge on the line number within the left-hand side of the editor. Netbeans
will offer you some assistance in determining the cause of the error if you hover your mouse over the red
error badge or underline.
Now that we have coded the first class in our stand-alone Jython application, it is time to take a look
at the implementation code. The HockeyRoster.py module is the heart of our roster application, as it
controls what is done with the team. We will use the shelve technique to store our Player objects to disk
for the roster application. As you can see from the following code, this is a very basic application and is
much the same as the implementation that will be found in the next chapter using Hibernate
persistence.
Listing 11-16.
# HockeyRoster.py
#
# Implementation logic for the HockeyRoster application
217
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
# Import Player class from the Player module
from Player import Player
# Import shelve for storage to disk
import shelve
class HockeyRoster:
def __init__(self):
self.player_data = shelve.open("players")
def make_selection(self):
'''
Creates a selector for our application. The function prints output to the
command line. It then takes a parameter as keyboard input at the command
line in order to choose our application option.
'''
options_dict = {1:self.add_player,
2:self.print_roster,
3:self.search_roster,
4:self.remove_player}
print "Please chose an option\n"
selection = raw_input('''Press 1 to add a player, 2 to print the roster,
3 to search for a player on the team,
4 to remove player, 5 to quit: ''')
if int(selection) not in options_dict:
if int(selection) == 5:
print "Thanks for using the HockeyRoster application."
else:
print "Not a valid option, please try again\n"
self.make_selection()
else:
func = options_dict[int(selection)]
if func:
func()
else:
print "Thanks for using the HockeyRoster application."
def add_player(self):
'''
Accepts keyboard input to add a player object to the roster list.
This function creates a new player object each time it is invoked
and appends it to the list.
'''
add_new = 'Y'
print "Add a player to the roster by providing the following information\n"
while add_new.upper() == 'Y':
first = raw_input("First Name: ")
last = raw_input("Last Name: ")
position = raw_input("Position: ")
id = self.return_player_count() + 1
218
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
print id
#set player and shelve
player = Player(id, first, last, position)
self.player_data[str(id)] = player
print "Player successfully added to the roster\n"
add_new = raw_input("Add another? (Y or N)")
self.make_selection()
def print_roster(self):
'''
Prints the contents of the list to the command line as a report
'''
print "====================\n"
print "Complete Team Roster\n"
print "======================\n\n"
player_list = self.return_player_list()
for player in player_list:
print "%s %s - %s" % (player_list[player].first,
player_list[player].last, player_list[player].position)
print "\n"
print "=== End of Roster ===\n"
self.make_selection()
def search_roster(self):
'''
Takes input from the command line for a player's name to search within the
roster list. If the player is found in the list then an affirmative message
is printed. If not found, then a negative message is printed.
'''
index = 0
found = False
print "Enter a player name below to search the team\n"
first = raw_input("First Name: ")
last = raw_input("Last Name: ")
position = None
player_list = self.return_player_list()
for player_key in player_list:
player = player_list[player_key]
if player.first.upper() == first.upper() and \
player.last.upper() == last.upper():
position = player.position
if position:
print '%s %s is in the roster as %s' % (first, last, position)
else:
print '%s %s is not in the roster.' % (first, last)
self.make_selection()
def remove_player(self):
'''
219
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Removes a player from the list
'''
index = 0
found = False
print "Enter a player name below to remove them from the team roster\n"
first = raw_input("First Name: ")
last = raw_input("Last Name: ")
position = None
player_list = self.return_player_list()
found_player = None
for player_key in player_list:
player = player_list[player_key]
if player.first.upper() == first.upper() and \
player.last.upper() == last.upper():
found_player = player
break
if found_player:
print '''%s %s is in the roster as %s,
are you sure you wish to remove?''' % (found_player.first,
found_player.last,
found_player.position)
yesno = raw_input("Y or N")
if yesno.upper() == 'Y':
# remove player from shelve
print 'The player has been removed from the roster',
found_player.id
del(self.player_data[str(found_player.id)])
else:
print 'The player will not be removed'
else:
print '%s %s is not in the roster.' % (first, last)
self.make_selection()
def return_player_list(self):
return self.player_data
def return_player_count(self):
return len(self.player_data)
# main
#
# This is the application entry point. It simply prints the applicaion title
# to the command line and then invokes the makeSelection() function.
if __name__ == "__main__":
print "Hockey Roster Application\n\n"
hockey = HockeyRoster()
hockey.make_selection()
The code should be relatively easy to follow at this point in the book. The main function initiates the
process as expected, and as you see it either creates or obtains a reference to the shelve or dictionary
where the roster is stored. Once this occurs the processing is forwarded to the make_selection() function
that drives the program. The important thing to note here is that, when using Netbeans, the code is laid
220
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
out nicely, and that code completion will assist with imports and completion of various code blocks. To
run your program, you can either right-click (Ctrl+click) on the project or set the project as the main
project within Netbeans and use the toolbar or pull-down menus. If everything has been set up
correctly, you should see the program output displaying in the Netbeans output window. You can
interact with the output window just as you would with the terminal.
Jython and Java Integrated Apps
Rather than repeat the different ways in which Jython and Java can be intermixed within an application,
this section will focus on how to do so from within the Netbeans IDE. There are various approaches that
can be taken in order to perform integration, and this section will not cover all of them. However, the
goal is to provide you with some guidelines and examples to use when developing integrated Jython and
Java applications within Netbeans.
Using a JAR or Java Project in Your Jython App
Making use of Java from within a Jython application is all about importing and ensuring that you have
the necessary Java class files and/or JAR files in your classpath. In order to achieve this technique
successfully, you can easily ensure that all of the necessary files will be recognized by the Netbeans
project. Therefore, the focus of this section is on using the Python project properties to set up the
sys.path for your project. To follow along, go ahead and use your HockeyRoster Jython project that was
created earlier in this section.
Let’s say that we wish to add some features to the project that are implemented in a Java project
named HockeyIntegration that we are coding in Netbeans. Furthermore, let’s assume that the
HockeyIntegration Java project compiles into a JAR file. Let's set up the HockeyIntegration project by
choosing New>Project. When the New Project window appears, select Java as the category, and Java
Application as the project and click Next. Now make sure you name your application HockeyIntegration
and click Finish. See Figure 11-8.
Your java application is now created and you are ready to begin development. In order to use this
project from within our HockeyRoster project, you’ll need to open up the project properties by rightclicking on your Jython project and choosing the Properties option. Once the window is open, click on
the Python menu item on the left-hand side of the window. This will give you access to the sys.path so
you can add other Python modules, eggs, Java classes, JAR files, and so on. Click on the Add button and
then traverse to the project directory for the Java application you are developing. Once there, go to the
dist directory and select the resulting JAR file and click OK. You can now use any of the Java project's
features from within your Jython application.
221
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Figure 11-8.
If you are interested in utilizing a Java API that exists within the standard Java library, then you are
in great shape. As you should know by now, Jython automatically provides access to the entire Java
standard library. You merely import the Java classes that you wish to use within your Jython application
and begin using, nothing special to set up within Netbeans. At the time of this writing, the Netbeans
Python EA did not support import completion for the standard Java library. However, we suspect that
this feature will be added in a subsequent release.
Using Jython in Java
If you are interested in using Jython or Python modules from within your Java applications, Netbeans
makes it easy to do. As mentioned in Chapter 10, the most common method of utilizing Jython from Java
is to use the object factory pattern. However, there are other ways to do this, such as using the clamp
project, which is not yet production-ready at the time of writing. For the purposes of this section, we’ll
discuss how to utilize another Netbeans Jython project as well as other Jython modules from within your
Java application using the object factory pattern.
In order to effectively demonstrate the use of the object factory pattern from within Netbeans, we’ll
be making use of the PlyJy project, which provides object factory implementations that can be used out
of the box. If you haven’t done so already, go to the Project Kenai site find the PlyJy project and
download the provided JAR. We will use the Netbeans project properties window in our Java project to
add this JAR file to our project. Doing so will effectively diminish the requirement of coding any object
factory implementations by hand and we'll be able to directly utilize Jython classes in our project.
Create a Java project named ObjectFactoryExample by selecting New>Project>Java Application.
Once you’ve done so, right-click (Cntrl+click) on the project and choose Properties. Once the project
properties window appears, click the Libraries option on the left-hand side. From there, add the PlyJy
JAR file that you previously downloaded to your project classpath. You will also have to add the
jython.jar file for the appropriate version of Jython that you wish to use. In our case, we will utilize the
Jython 2.5.1 release. See Figure 11-9.
222
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Figure 11-9. Adding the JAR file
The next step is to ensure that any and all Jython modules that you wish to use are in your
CLASSPATH somewhere. This can be easily done by either adding them to your application as regular
code modules somewhere and then going into the project properties window and including that
directory in the Compile-Time Libraries list contained the Libraries section, or by clicking the Add
JAR/Folder button. Although this step may seem unnecessary because the modules are already part of
your project, it must be done in order to place them into your CLASSPATH. Once they’ve been added to
the CLASSPATH successfully, you can begin to make use of them via the object factory pattern. Netbeans
will seamlessly use the modules in your application as if all of the code was written in the same language.
At this point your project should be set up and ready for using object factories. To learn more about
using object factories, please refer to Chapter 10.
The Netbeans Python Debugger
As mentioned previously, the Netbeans IDE also includes a Python debugger that is derived from JeanYves Mengant’s jpydbg debugger. This section will discuss how to make use of the Netbeans Python
debugger along with some examples using our HockeyRoster code that was written in the previous
section. If you have used a debugger in another IDE, or perhaps the Java debugger that is available for
Netbeans, this debugger will feel quite familiar. The Python debugger includes many features such as
breakpoints, run-time local variable values, code stepping, and more.
223
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Prior to using the debugger, it may be useful to take a look at the debugger preferences by
navigating to the Netbeans Preferences>Python Options>Debugger window. From there you will see
that you have the ability to change the debugger port, code coloring for debugging sessions, and to stop
at the first line of the script or continue until the debugger reaches the first breakpoint. To make the
debugger feel and act similar to the Netbeans Java debugger, you may want to de-select the “Stop at the
first line” checkbox. Otherwise the debugger will not load your module right away, but rather stop
execution at the first line of your module and wait for you to continue. See Figure 11-10.
Figure 11-10. The Netbeans Python debugger
Making use of the Python debugger included with Netbeans is much like working from the Jython
interactive interpreter from the command-line or terminal window. If you have selected the “Stop at first
line” checkbox in the debugger preferences, the debugger will halt at the first line of code in your main
module and you must use the debugger Continue button to move to the first line of code that is
executed. However, if you have de-selected the checkbox, then the module will automatically run your
program until it reaches the first breakpoint. For the purposes of this exercise, let’s keep the checkbox
selected. In order to set a breakpoint, click on the margin to the left of the line in your code where you
would like the debugger to halt program execution. In our case, let’s open the HockeyRoster.py module
and set a breakpoint in the code as shown in Figure 11-11.
224
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Figure 11-11. Setting a breakpoint in the code
Now that we’ve set a breakpoint, we need to start our debugger. However, prior to debugging it is
important to make sure that Netbeans knows which module to use for starting the program. To do so,
right-click on your project and select Properties. When the properties window opens, select Run in the
left-hand side of the window. You should now type or browse to the module that you wish to use as a
starting point for your program. See Figure 11-12.
Figure 11-12. Click Browse to select the module you wish to use as a starting point.
Note that this may already be automatically filled in for you by Netbeans. Once you’ve ensured that
you have set the main module, you can begin the debugging session. To do so, you can either select your
program and use the Debug menu option, or you can right-click on the project and select Debug. Once
you’ve started the debugger, you will see a series of messages appearing in the debugging window near
the bottom of the IDE window to indicate that the debugger has been started. After a few seconds, you
225
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
will see the messages stop writing in the debugger output window, and the editor will focus on the first
line of code in your main module and highlight it in green. See Figure 11-13.
Figure 11-13. Beginning the debugging session
To continue the debugger to the first line of code that is executed, select the green Continue button
in the toolbar, or press the F5 key. You should see the program will begin to execute within the debugger
output window and it will halt to allow us to enter a selection. See Figure 11-14.
Figure 11-14. The debugger output window
Make sure your cursor is within the debugger output window and enter 1 to add a player. When you
hit the Enter button to continue, the program will not continue to execute, but instead it will halt at the
breakpoint that we have set up. In the editor you will see the line which we added a breakpoint to is now
highlighted in green. The debugger has suspended state at this point in the program, and this affords us
the ability to perform tasks to see exactly what is occurring at this point in the program. For instance, if
you select the Variables tab in the lower portion of the Netbeans IDE, you will be able to see the values of
all local variables at this current point in the program. See Figure 11-15.
Figure 11-15. The values of all local variables at this current point in the program
226
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
You can also select the Call Stack tab to see the execution order of your program to this point. See
Figure 11-16.
Figure 11-16. The execution order of your program
Once you’ve evaluated the program at the breakpoint, you can continue the program execution by
stepping forward through the code using the buttons in the toolbar. You can also click the Continue
button to run the program until it reaches the next breakpoint, or in this case because we have no more
breakpoints, it will just continue the program execution as normal. The debugger is especially helpful if
you are attempting to evaluate a specific line of code or portion of your program by stepping through the
code and executing it line by line.
Another nice feature of the debugger is that you can set certain conditions on breakpoints. To do so,
set a breakpoint in your code and then right-click on the breakpoint and select Breakpoint and then
Properties from the resulting window. At this point you will see the additional breakpoint options. In this
case, set up a condition that will cause the debugger to halt only if the selection variable is equal to 3, as
shown in Figure 11-17.
Figure 11-17. Setting a condition for halting the debugger
At this point you can run the debugger again, and if you select the option of 3 during your program
execution you will notice that the debugger will halt.
227
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
The Netbeans Python debugger offers enough options to fill up an entire chapter worth of reading,
but hopefully the content covered in this section will help you get started. Once you’ve mastered the use
of the debugger, it can save you lots of time.
Other Netbeans Python Features
There are a number of additional features in the Netbeans Python IDE support that we haven’t touched
upon yet. For instance, minimal refactoring support is available for any Python module. By right-clicking
on the module in the project navigator or within a module, a bevy of additional options become
available to you via the right-click menu. You’ll see that there is a Refactoring option that becomes
available. However at the time of this writing the only available refactoring options were Rename, Move,
Copy, and Safely Delete. There is a Navigate feature that allows for one to perform shortcuts such as
highlighting a variable and finding its declaration. The Navigate feature also allows you to jump to any
line in your code by simply providing a line number. If your Python class is inheriting from some other
object, you can use the Navigate feature to quickly go to the super implementation. It is easy to find the
usages of any Python module, method, function, or variable by using the Find Usages feature. If your
code is not formatted correctly, you can quickly have the IDE format it for you by choosing the Format
option, which is also available in the right-click menu.
Another nice feature that is available in the right-click menu is Insert Code. This feature allows you
to choose from a number of different templates in order to have the IDE auto-generate code for you.
Once you select the Insert Code option, another menu appears allowing you to choose from a code
templates including Property, Constructor, Method, and Class. Once a template is chosen, the IDE autogenerates the code to create a generic Python property, constructor, method, or class. You can then
refine the automatically generated code to your needs. This feature allows the developer to type less, and
if used widely throughout a program it can ensure that code is written in a consistent manner. See Figure
11-18.
Figure 11-18. The very handy Insert Code option
Another nice feature is Fast Import. This allows you to highlight an object in your code and
automatically have the IDE import the required module for using the object. You also have the ability to
Fix Imports, which will automatically clean up unused imports in your code.
Along with all of the other features that are available with the Netbeans IDE, these additional
features are like the icing on the cake! Keep in mind that you are not required to right-click each time
that you wish to use one of these additional features, there are also keyboard shortcuts for each of them.
The keyboard shortcuts will differ depending upon which operating system you are using.
228
www.it-ebooks.info
CHAPTER 11 ■ USING JYTHON IN AN IDE
Summary
As with most other programming languages, you have several options to use for an IDE when developing
Jython. In this chapter we covered two of the most widely used IDE options for developing Jython
applications, Netbeans and Eclipse. Eclipse offers a truly complete IDE solution for developing Jython
applications, both stand alone and web-based. PyDev is under constant development and always getting
better, adding new features and streamlining existing features.
Netbeans Jython support is in still in development at the time of this writing. Many of the main
features such as code completion and syntax coloring are already in place. It is possible to develop
Jython applications including Jython and Java integration as well as web-based applications. In the
future, Netbeans Jython support will develop to include many more features and they will surely be
covered in future releases of this book.
In the next chapter, we will take a look at developing some applications utilizing databases. The
zxJDBC API will be covered and you’ll learn how to develop Jython applications utilizing standard
database transactions. Object relational mapping is also available for Jython in various forms, we'll
discuss many of those options as well.
229
www.it-ebooks.info
www.it-ebooks.info
C H A P T E R 12
■■■
Databases and Jython:
Object Relational Mapping
and Using JDBC
In this chapter, we will look at zxJDBC package, which is a standard part of Jython since version 2.1 and
complies with the Python 2.0 DBI standard. zxJDBC can be an appropriate choice for simple one-off
scripts where database portability is not a concern. In addition, it’s (generally) necessary to use zxJDBC
when writing a new dialect for SQLAlchemy or Django. (But that’s not strictly true: you can use pg8000, a
pure Python DBI driver, and of course write your own DBI drivers. But please don’t do that.) So knowing
how zxJDBC works can be useful when working with these packages. However, it’s too low level for us to
recommend for more general usage. Use SQLAlchemy or Django if at all possible. Finally, JDBC itself is
also directly accessible, like any other Java package from Jython. Simply use the java.sql package. In
practice this should be rarely necessary.
The second portion of this chapter will focus on using object relational mapping with Jython. The
release of Jython 2.5 has presented many new options for object relational mapping. In this chapter we’ll
focus on using SQLAlchemy with Jython, as well as using Java technologies such as Hibernate. In the end
you should have a couple of different choices for using object relational mapping in your Jython
applications.
ZxJDBC—Using Python’s DB API via JDBC
The zxJDBC package provides an easy-to-use Python wrapper around JDBC. zxJDBC bridges two
standards:
•
JDBC is the standard platform for database access in Java.
•
DBI is the standard database API for Python apps.
ZxJDBC, part of Jython, provides a DBI 2.0 standard compliant interface to JDBC. Over 200 drivers
are available for JDBC (http://developers.sun.com/product/jdbc/drivers), and they all work with
zxJDBC. High performance drivers are available for all major relational databases, including DB2, Derby,
MySQL, Oracle, PostgreSQL, SQLite, SQL Server, and Sybase. And drivers are also available for nonrelational and specialized databases, too.
However, unlike JDBC, zxJDBC when used in the simplest way possible, blocks SQL injection
attacks, minimizes overhead, and avoids resource exhaustion. In addition, zxJDBC defaults to using a
transactional model (when available), instead of autocommit.
First we will look at connections and cursors, which are the key resources in working with zxJDBC,
just like any other DBI package. Then we will look at what you can do them with them, in terms of typical
queries and data manipulating transactions.
231
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
Getting Started
The first step in developing an application that utilizes a database back-end is to determine what
database or databases the application will use. In the case of using zxJDBC or another JDBC
implementation, the determination of what database the application will make use of is critical to the
overall development process. Many application developers will choose to use an object relational
mapper for this very reason. When an application is coded with a JDBC implementation, whereas SQL
code is hand-coded, the specified database of choice will cause different dialects of SQL to be used. One
of the benefits of object relation mapping (ORM) technology is that the SQL is transparent to the
developer. The ORM technology takes care of the different dialects behind the scenes. This is one of the
reasons why ORM technology may be slower at implementing support for many different databases.
Take SQLAlchemy or Django for instance: each of these technologies must have a different dialect coded
for each database. Using an ORM can make an application more portable over many different databases.
However, as stated in the preface using zxJDBC would be a fine choice if your application is only going to
target one or two databases.
While using JDBC for Java, one has to deal with the task of finding and registering a driver for the
database. Most of the major databases make their JDBC drivers readily available for use. Others may
make you register prior to downloading the driver, or in some cases purchase it. Because zxJDBC is an
alternative implementation of JDBC, one must use a JDBC driver in order to use the API. Most JDBC
drivers come in the format of a JAR file that can be installed to an application server container, and IDE.
In order to make use of a particular database driver, it must reside within the CLASSPATH. As mentioned
previously, to find a given JDBC driver for a particular database, take a look at the Sun Microsystems
JDBC Driver search page (http://developers.sun.com/product/jdbc/drivers) as it contains a listing of
different JDBC drivers for most of the databases available today.
■ Note Examples in this section are for Jython 2.5.1 and later. Jython 2.5.1 introduced some simplifications for working
with connections and cursors. In addition, we assume PostgreSQL for most examples, using the world sample database
(also available for MySQL). In order to follow along with the examples in the following sections, you should have a
PostgreSQL database available with the world database example. Please go to the PostgreSQL homepage at
http://www.postgresql.org to download the database. The world database sample is available with the source for this
book. It can be installed into a PostgreSQL database by opening psql and initiating the following command:
postgres=# \i /world.sql
As stated previously, once a driver has been obtained it must be placed into the classpath. What
follows are a few examples for adding JDBC drivers to the CLASSPATH for a couple of the most popular
databases.
Listing 12-1. Adding JDBC drivers for popular databases to the CLASSPATH
# Oracle
# Windows
set CLASSPATH=\ojdbc14.jar;%CLASSPATH%
# OS X
232
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
export CLASSPATH=/ojdbc14.jar:$CLASSPATH
# PostgreSQL
# Windows
set CLASSPATH=\postgresql-x.x.jdbc4.jar;%CLASSPATH%
# OS X
export CLASSPATH=/postgresql-x.x.jdbc4.jar:$CLASSPATH
After the appropriate JAR file for the target database has been added to the CLASSPATH,
development can commence. It is important to note that zxJDBC (and all other JDBC implementations)
use a similar procedure for working with the database. One must perform the following tasks to use a
JDBC implementation:
•
Create a connection.
•
Create a query or statement.
•
Obtain results of query or statement.
•
If using a query, obtain results in a cursor and iterate over data to perform tasks.
•
Close cursor.
•
Close connection (If not using the with_statement syntax in versions of Jython
prior to 2.5.1).
Over the next few sections, we’ll take a look at each of these steps and how zxJDBC can make them
easier than using JDBC directly.
Connections
A database connection is simply a resource object that manages access to the database system. Because
database resources are generally expensive objects to allocate, and can be readily exhausted, it is
important to close them as soon as you're finished using them. There are two ways to create database
connections:
•
Direct creation. Standalone code, such as a script, will directly create a connection.
•
JNDI. Code managed by a container should use JNDI for connection creation.
Such containers include GlassFish, JBoss, Tomcat, WebLogic, and WebSphere.
Normally connections are pooled when run in this context and are also associated
with a given security context.
The following is an example of the best way to create a database connection outside of a managed
container using Jython 2.5.1. It is important to note that prior to 2.5.1, the with_statement syntax was not
available. This is due to the underlying implementation of PyConnection in versions of Jython prior to
2.5.1. As a rule, any object that can be used via the with_statement must implement certain functionality,
including the __exit__ method. Please see the note that follows to find out how to implement this
functionality in versions prior to 2.5.1. Another thing to notice is that in order to connect, we must use a
JDBC url which conforms to the standards of a given database in this case, PostgreSQL.
Listing 12-2. py
from __future__ import with_statement
from com.ziclix.python.sql import zxJDBC
233
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
# for example
jdbc_url = "jdbc:postgresql:test"
username = "postgres"
password = "jython25"
driver = "org.postgresql.Driver"
# obtain a connection using the with-statment
with zxJDBC.connect(jdbc_url, username, password, driver) as conn:
with conn:
with conn.cursor() as c:
c.execute("select name from country")
c.fetchone()
Walking through the steps, you can see that the with_statement and zxJDBC are imported as we will
use them to obtain our connection. The next step is to define a series of string values that will be used for
the connection activity. Note that these only need to be defined once if set up as globals. Lastly, the
connection is obtained and some work is done. Now let’s take a look at this same procedure coded in
Java for comparison.
Listing 12-3.
import java.sql.*;
import org.postgresql.Driver;
...
// In some method
Connection conn = null;
String jdbc_url = "jdbc:postgresql:test";
String username = "postgres";
String password = "jython25";
String driver = "org.postgresql.Driver";
try {
DriverManager.registerDriver(new org.postgresql.Driver());
conn = DriverManager.getConnection(jdbc_url,
username, password);
// do something using statement and resultset
conn.close();
}
catch(Exception e) {
logWriter.error("getBeanConnection ERROR: ",e);
}
■ Note In versions of Jython prior to 2.5.1, the with_statement syntax is not available. For this reason, we must
work directly with the connection (i.e. close it when finished). Take a look at the following code for an example of
using zxJDBC connections without the with_statement functionality.
from __future__ import with_statement from com.ziclix.python.sql import zxJDBC
234
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
# for example jdbc_url = "jdbc:postgresql:test" username = "postgres" password = "jython25" driver =
"org.postgresql.Driver"
conn = zxJDBC.connect(jdbc_url, username, password, driver) do_something(conn) # Be sure to clean up by
closing the connection (and cursor) conn.close()
The with statement ensures that the connection is immediately closed following the work. The
alternative is to use finally to perform the close. Using the latter technique allows for more tightly
controlled exception handling technique, but also adds a considerable amount of code. As noted
previously, the with statement is not available in versions of Jython prior to 2.5.1, so this is the
recommended approach when using those versions:
Listing 12-4.
try:
conn = zxJDBC.connect(jdbc_url, username, password, driver)
do_something(conn)
finally:
conn.close()
The connection (PyConnection) object in zxJDBC has a number of methods and attributes that can
be used to perform various functions and obtain metadata information. For instance, the close method
can be used to close the connection. Tables 12-1 and 12-2 are listings of all available methods and
attributes for a connection and what they do.
Table 12-1. Connection Methods
Method
Functionality
close
Close the connection now (rather than whenever __del__ is called).
commit
Commits all work that has been performed against a connection.
cursor
Returns a new cursor object from the connection.
rollback
In case a database does provide transactions, this method causes the database to roll back
to the start of any pending transaction.
nativesql
Converts the given SQL statement into the system's native SQL grammar.
autocommit Enable or disable autocommit on a connection. Default is disabled.
dbname
Returns the name of the database.
235
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
Table 12-2. Connection Attributes (continued)
Method
Functionality
dbversion
Returns the version of database.
drivername
Returns the database driver name.
driverversion
Returns the database driver version.
closed
Returns a Boolean stating whether connection is closed.
Of course, we can always use the connection to obtain a listing of all methods and attributes using
the syntax shown in Listing 12-5.
Listing 12-5.
>>> conn.__methods__
['close', 'commit', 'cursor', 'rollback', 'nativesql']
>>> conn.__members__
['autocommit', 'dbname', 'dbversion', 'drivername', 'driverversion', 'url',
'__connection__', '__cursors__', '__statements__', 'closed']
■ Note Connection pools help ensure for more robust operation, by providing for reuse of connections while
ensuring the connections are in fact valid. Often naive code will hold a connection for a very long time, to avoid the
overhead of creating a connection, and then go to the trouble of managing reconnecting in the event of a network
or server failure. It's better to let that be managed by the connection pool infrastructure instead of reinventing it.
All transactions, if supported, are done within the context of a connection. We will be discussing
transactions further in the subsection on data modification, but Listing 12-6 is the basic recipe.
Listing 12-6. Transaction Recipe
try:
# Obtain a connection that is not using auto-commit (default for zxJDBC)
conn = zxJDBC.connect(jdbc_url, username, password, driver)
# Perform all work on connection
do_something(conn)
# After all work is complete, commit
conn.commit()
except:
236
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
# If a failure occurs along the way, rollback all previous work
conn.rollback()
ZxJDBC.lookup
In a managed container, you would use zxJDBC.lookup instead of zxJDBC.connect. If you have code that
needs to run both inside and outside containers, we recommend you use a factory to abstract this. Inside
a container, like an app server, you should use JDNI to allocate the resource. Generally the connection
will be managed by a connection pool (see Listing 12-7).
Listing 12-7.
factory = "com.sun.jndi.fscontext.RefFSContextFactory"
db = zxJDBC.lookup('jdbc/postgresDS',
INITIAL_CONTEXT_FACTORY=factory)
This example assumes that the datasource defined in the container is named “jdbc/postgresDS,”
and it uses the Sun FileSystem JNDI reference implementation. This lookup process does not require
knowing the JDBC URL or the driver factory class. These aspects, as well as possibly the user name and
password, are configured by the administrator of the container using tools specific to that container.
Most often by convention you will find that JNDI names typically resemble a jdbc/NAME format.
Cursors
Once you have a connection, you probably want to do something with it. Because you can do multiple
things within a transaction, such as query one table, update another, you need one more resource,
which is a cursor. A cursor in zxJDBC is a wrapper around the JDBC statement and resultSet objects that
provides a very Pythonic syntax for working with the database. The result is an easy to use and extremely
flexible API. Cursors are used to hold data that has been obtained via the database, and they can be used
in a variety of fashions which we will discuss. There are two types of cursors available for use, static and
dynamic. A static cursor is the default type, and it basically performs an iteration on an entire resultSet at
once. The latter dynamic cursor is known as a lazy cursor and it only iterates through the resultSet on an
as-needed basis. The following listings are examples of creating each type of cursor.
Listing 12-8. Creating all possible cursor types
# Assume that necessary imports have been performed
# and that a connection has been obtained and assigned
# to a variable 'conn'
cursor = conn.cursor() # static cursor creation
cursor = conn.cursor(True) # dynamic cursor creation with the Boolean argument
Dynamic cursors tend to perform better due to memory constraints; however, in some cases they
are not as convenient as working with a static cursor. For example, if you’d like to query the database to
find a row count it is very easy with a static cursor because all rows are obtained at once. This is not
possible with a dynamic cursor and one must perform two queries in order to achieve the same result.
237
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
Listing 12-9.
# Using a static cursor to obtain rowcount
>>> cursor = conn.cursor()
>>> cursor.execute("select * from country")
>>> cursor.rowcount
239
# Using a dynamic cursor to obtain rowcount
>>> cursor = conn.cursor(1)
>>> cursor.execute("select * from country")
>>> cursor.rowcount
0
# Since rowcount does not work with dynamic, we must
# perform a separate count query to obtain information
>>> cursor.execute("select count(*) from country")
>>> cursor.fetchone()
(239L,)
Cursors are used to execute queries, inserts, updates, deletes, and/or issue database commands.
Like connections, cursors have a number of methods and attributes that can be used to perform actions
or obtain metadata information. See Tables 12-3 and 12-4.
Table 12-3. Cursor Methods
Method
Functionality
tables
Retrieves a list of tables (catalog, schema-pattern, table-pattern, types).
columns
Retrieves a list of columns (catalog, schema-pattern, table-name-pattern, columnname-pattern).
primarykeys
Retrieves a list of primary keys (catalog, schema, table).
foreignkeys
Retrieves a list of foreign keys (primary-catalog, primary-schema, primary-table,
foreign-catalog, foreign-schema, foreign-table).
procedures
Retrieves a list of procedures (catalog, schema, tables).
procedurecolumns
Retrieves a list of procedure columns (catalog, schema-pattern, procedurepattern, column-pattern).
statistics
Obtains statistics on the query (catalog, schema, table, unique, approximation).
bestrow
Optimal set of columns that uniquely identify a row.
238
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
Table 12-3. Cursor Methods (continued)
Method
Functionality
versioncolumns
Columns that are automatically updated when any value in a row is updated.
close
Closes the cursor.
execute
Executes code contained within the cursor.
executemany
Used to execute prepared statements or sql with a parameter list.
fetchone
Fetch the next row of a query result set, returning a single sequence, or None if no
more data exists.
fetchall
Fetch all (remaining) rows of a query result, returning them as a sequence of
sequences.
fetchmany
Fetch the next set of rows of a query result, returning a sequence of sequences.
callproc
Executes a stored procedure.
next
Moves to the next row in the cursor.
write
Execute the sql written to this file-like object.
Table 12-4. Cursor Attributes
Attribute
Functionality
arraysize
Number of rows fetchmany() should return without any arguments.
rowcount
Returns the number of resulting rows.
rownumber Returns the current row number.
description Returns information regarding each column in the query.
datahandler Returns the specified datahandler.
warnings
Returns all warnings on the cursor.
239
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
Table 12-4. Cursor Attributes (continued)
Attribute
Functionality
lastrowid
Returns the rowid of the last row fetched.
updatecount
Returns the number of updates that the current cursor has performed.
closed
Returns a boolean representing whether the cursor has been closed.
connection
Returns the connection object that contains the cursor.
A number of the methods and attributes above cannot be used until a cursor has been executed
with a query or statement of some kind. Most of the time, the particular method or attribute name will
provide a good enough description of its functionality.
Creating and Executing Queries
As you’ve seen previously, it is quite easy to initiate a query against a given cursor. Simply provide a
select statement in string format as a parameter to the cursor execute() or executemany() methods and
then use one of the fetch methods to iterate over the returned results. In the following examples we
query the world data and display some cursor data via the associated attributes and methods.
Listing 12-10.
>>> cursor = conn.cursor()
>>> cursor.execute("select country, region from country")
# Fetch next record
>>> cursor.fetchone()
((AFG,Afghanistan,Asia,"Southern and Central
Asia",652090,1919,22720000,45.9,5976.00,,Afganistan/Afqanestan,"Islamic Emirate","Mohammad
Omar",1,AF), u'Southern and Central Asia')
# Calling fetchmany() without any parameters returns next record
>>> cursor.fetchmany()
[((NLD,Netherlands,Europe,"Western
Europe",41526,1581,15864000,78.3,371362.00,360478.00,Nederland,"Constitutional
Monarchy",Beatrix,5,NL), u'Western Europe')]
# Fetch the next two records
>>> cursor.fetchmany(2)
[((ANT,"Netherlands Antilles","North
America",Caribbean,800,,217000,74.7,1941.00,,"Nederlandse Antillen","Nonmetropolitan
Territory of The Netherlands",Beatrix,33,AN), u'Caribbean'), ((ALB,Albania,Europe,"Southern
Europe",28748,1912,3401200,71.6,3205.00,2500.00,Shqip?ria,Republic,"Rexhep Mejdani",34,AL),
u'Southern Europe')]
240
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
# Calling fetchall() would retrieve the rest of the records
>>> cursor.fetchall()
...
# Using description provides data regarding the query in the cursor
>>> cursor.description
[('country', 1111, 2147483647, None, None, None, 2), ('region', 12, 2147483647, None, None,
None, 0)]
Creating a cursor using the with_statement syntax is easy, please take a look at the following
example for use with Jython 2.5.1 and beyond.
Listing 12-11.
with conn.cursor() as c:
do_some_work(c)
Like connections, you need to ensure the resource is appropriately closed. So you can just do this to
follow the shorter examples we will look at:
Listing 12-12.
>>> c = conn.cursor()
>>> # work with cursor
As you can see, queries are easy to work with using cursors. In the previous example, we used the
fetchall() method to retrieve all of the results of the query. However, there are other options available for
cases where all results are not desired including the fetchone() and fetchmany() options. Sometimes it is
best to iterate over results of a query in order to work with each record separately. Listing 12-13 iterates
over the countries contained within the country table.
Listing 12-13.
>>> from com.ziclix.python.sql import zxJDBC
>>> conn =
zxJDBC.connect("jdbc:postgresql:test","postgres","jython25","org.postgresql.Driver")
>>> cursor = conn.cursor()
>>> cursor.execute("select name from country")
>>> while cursor.next():
...
print cursor.fetchone()
...
(u'Netherlands Antilles',)
(u'Algeria',)
(u'Andorra',)
...
Often, queries are not hard-coded, and we need the ability to substitute values in the query to select
the data that our application requires. Developers also need a way to create dynamic SQL statements at
times. Of course, there are multiple ways to perform these feats. The easiest way to substitute variables
or create a dynamic query is to simply use string concatenation. After all, the execute() method takes a
241
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
string-based query. Listing 12-14 shows how to use string concatenation for dynamically forming a
query and also substituting variables.
Listing 12-14. String Concatenation for Dynamic Query Formation
#
#
#
#
Assume that the user selected
what results to retrieve from
The selected choice is stored
that we are interested in all
a pull-down menu choice determining
the database, either continent or country name.
in the selectedChoice variable. Let's also assume
continents or countries beginning with the letter "A"
>>> qry = "select " + selectedChoice + " from country where " + selectedChoice + " like
'A%'"
>>> cursor.execute(qry)
>>> while cursor.next():
...
print cursor.fetchone()
...
(u'Albania',)
(u'American Samoa',)
...
This technique works very well for creating dynamic queries, but it also has its share of issues. For
instance, reading through concatenated strings of code can become troublesome on the eyes.
Maintaining such code is a tedious task. Above that, string concatenation is not the safest way to
construct a query as it opens an application up for a SQL injection attack. SQL injection is a technique
that is used to pass undesirable SQL code into an application in such a way that it alters a query to
perform unwanted tasks. If the user has the ability to type free text into a textfield and have that text
passed into a string concatenated query, it is best to perform some other means of filtering to ensure
certain keywords or commenting symbols are not contained in the value. A better way of getting around
these issues is to make use of prepared statements.
■ Note Ideally, never construct a query statement directly from user data. SQL injection attacks employ such
construction as their attack vector. Even when not malicious, user data will often contain characters, such as
quotation marks, that can cause the query to fail if not properly escaped. In all cases, it’s important to scrub and
then escape the user data before it’s used in the query.
One other consideration is that such queries will generally consume more resources unless the database
statement cache is able to match it (if at all).
But there are two important exceptions to our recommendation:
SQL statement requirements: Bind variables cannot be used everywhere. However, specifics will depend
on the database.
Ad hoc or unrepresentative queries: In databases like Oracle, the statement cache will cache the execution
plan, without taking in account lopsided distributions of values that are indexed, but are known to the
database if presented literally. In those cases, a more efficient execution plan will result if the value is put in
the statement directly.
242
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
However, even in these exceptional cases, it's imperative that any user data is fully scrubbed. A good solution is to
use some sort of mapping table, either an internal dictionary or a mapping table driven from the database itself. In
certain cases, a carefully constructed regular expression may also work. Be careful.
Prepared Statements
To get around using the string concatenation technique for substituting variables, we can use a
technique known as prepared statements. Prepared statements allow one to use bind variables for data
substitution, and they are generally safer to use because most security considerations are taken care of
without developer interaction. However, it is always a good idea to filter input to help reduce the risk.
Prepared statements in zxJDBC work the same as they do in JDBC, just a simpler syntax. In Listing 12-15,
we will perform a query on the country table using a prepared statement. Note that the question marks
are used as place holders for the substituted variables. It is also important to note that the executemany()
method is invoked when using a prepared statement. Any substitution variables being passed into the
prepared statement must be in the form of a tuple or list.
Listing 12-15. Using Prepared Statements
# Passing a string value into the query
qry = "select continent from country where name = ?"
>>> cursor.executemany(qry,['Austria'])
>>> cursor.fetchall()
[(u'Europe',)]
# Passing some variables into the query
>>> continent1 = 'Asia'
>>> continent2 = 'Africa'
>>> qry = "select name from country where continent in (?,?)"
>>> cursor.executemany(qry, [continent1, continent2])
>>> cursor.fetchall()
[(u'Afghanistan',), (u'Algeria',), (u'Angola',), (u'United Arab Emirates',), (u'Armenia',),
(u'Azerbaijan',),
...
Resource Management
You should always close connections and cursors. This is not only good practice but absolutely essential
in a managed container so as to avoid exhausting the corresponding connection pool, which needs the
connections returned as soon as they are no longer in use. The with statement makes it easy. See Listing
12-16.
Listing 12-16. Managing Connections Using With Statements
from __future__ import with_statement
from itertools import islice
from com.ziclix.python.sql import zxJDBC
# externalize
jdbc_url = "jdbc:oracle:thin:@host:port:sid"
243
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
username = "world"
password = "world"
driver = "oracle.jdbc.driver.OracleDriver"
with zxJDBC.connect(jdbc_url, username, password, driver) as conn:
with conn:
with conn.cursor() as c:
c.execute("select * from emp")
for row in islice(c, 20):
print row # let's redo this w/ namedtuple momentarily...
The older alternative is available. It’s more verbose, and similar to the Java code that would
normally have to be written to ensure that the resource is closed. See Listing 12-17.
Listing 12-17. Managing Connections Avoiding the With Statement
try:
conn = zxJDBC.connect(jdbc_url, username, password, driver)
cursor = conn.cursor()
#do something with the cursor
# Be sure to clean up by closing the connection (and cursor)
finally:
if cursor:
cursor.close()
if conn:
conn.close()
Metadata
As mentioned previously in this chapter, it is possible to obtain metadata information via the use of
certain attributes that are available to both connection and cursor objects. zxJDBC matches these
attributes to the properties that are found in the JDBC java.sql.DatabaseMetaData object. Therefore,
when one of these attributes is called, the JDBC DatabaseMetaData object is actually obtaining the
information.
Listing 12-18 shows how to retrieve metadata about a connection, cursor, or even a specific query.
Note that whenever obtaining metadata about a cursor, you must fetch the data after setting up the
attributes.
Listing 12-18. Retrieving Metadata About a Connection, Cursor or Specific Query
# Obtain information about the connection using connection attributes
>>> conn.dbname
'PostgreSQL'
>>> conn.dbversion
'8.4.0'
>>> conn.drivername
'PostgreSQL Native Driver'
# Check for existing cursors
>>> conn.__cursors__
[]
244
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
# Obtain information about the cursor and the query
>>> cursor = conn.cursor()
# List all tables
>>> cursor.tables(None, None, '%', ('TABLE',))
>>> cursor.fetchall()
[(None, u'public', u'city', u'TABLE', None), (None, u'public', u'country', u'TABLE', None),
(None, u'public', u'countrylanguage', u'TABLE', None), (None, u'public', u'test', u'TABLE',
None)]
Data Manipulation Language and Data Definition Language
Any application that will manipulate data contained in a RDBMS must be able to issue Data
Manipulation Language (DML). Of course, DML consists of issuing statements such as INSERT,
UPDATE, and DELETE. . .the basics of CRUD programming. zxJDBC makes it rather easy to use DML in a
standard cursor object. When doing so, the cursor will return a value to provide information about the
result. A standard DML transaction in JDBC uses a prepared statement with the cursor object, and
assigns the result to a variable that can be read afterwards to determine whether the statement
succeeded.
ZxJDBC also uses cursors to define new constructs in the database using Data Definition Language
(DDL). Examples of doing such are creating tables, altering tables, creating indexes, and the like.
Similarly to performing DML with zxJDBC, a resulting DDL statement returns a value to assist in
determining whether the statement succeeded or not.
In the next couple of examples, we’ll create a table, insert some values, delete values, and finally
delete the table.
Listing 12-19. Using DML
# Create a table named PYTHON_IMPLEMENTATIONS
>>> stmt = "create table python_implementations (id integer, python_implementation varchar,
current_version varchar)"
>>> result = cursor.execute(stmt)
>>> print result
None
>>> cursor.tables(None, None, '%', ('TABLE',))
# Ensure table was created
>>> cursor.fetchall()
[(None, u'public', u'city', u'TABLE', None), (None, u'public', u'country', u'TABLE', None),
(None, u'public', u'countrylanguage', u'TABLE', None), (None, u'public',
u'python_implementations', u'TABLE',
None), (None, u'public', u'test', u'TABLE', None)]
# Insert some values into the table
>>> stmt = "insert into PYTHON_IMPLEMENTATIONS values (?, ?, ?)"
>>> result = cursor.executemany(stmt, [1,'Jython','2.5.1'])
>>> result = cursor.executemany(stmt, [2,'CPython','3.1.1'])
>>> result = cursor.executemany(stmt, [3,'IronPython','2.0.2'])
>>> result = cursor.executemany(stmt, [4,'PyPy','1.1'])
>>> conn.commit()
# Query the database
>>> cursor.execute("select python_implementation, current_version from
python_implementations")
>>> cursor.rowcount
245
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
4
>>> cursor.fetchall()
[(u'Jython', u'2.5.1'), (u'CPython', u'3.1.1'), (u'IronPython', u'2.0.2'), (u'PyPy',
u'1.1')]
# Update values and re-query
>>> stmt = "update python_implementations set python_implementation = 'CPython -Standard
Implementation' where id = 2"
>>> result = cursor.execute(stmt)
>>> print result
None
>>> conn.commit()
>>> cursor.execute("select python_implementation, current_version from
python_implementations")
>>> cursor.fetchall()
[(u'Jython', u'2.5.1'), (u'IronPython', u'2.0.2'), (u'PyPy', u'1.1'), (u'CPython -Standard
Implementation', u'3.1.1')]
It is a good practice to make use of bulk inserts and updates. Each time a commit is issued it incurs a
performance penalty. If DML statements are grouped together and then followed by a commit, the
resulting transaction will perform much better. Another good reason to use bulk DML statements is to
ensure transactional safety. It is likely that if one statement in a transaction fails, all others should be
rolled back. As mentioned previously in the chapter, using a try/except clause will maintain
transactional dependencies. If one statement fails then all others will be rolled back. Likewise, if they all
succeed then they will be committed to the database with one final commit.
Calling Procedures
Database applications often make use of procedures and functions that live inside the database. Most
often these procedures are written in a SQL procedural language such as Oracle’s PL/SQL or
PostgreSQL’s PL/pgSQL. Writing database procedures and using them with external applications such
written in Python, Java, or the like makes lots of sense, because procedures are often the easiest way to
work with data. Not only are they running close to the metal since they are in the database, but they also
perform much faster than say a Jython application that needs to connect and close connections on the
database. Since a procedure lives within the database, there is no performance penalty due to
connections being made.
ZxJDBC can easily invoke a database procedure just as JDBC can do. This helps developers to create
applications that have some of the more database-centric code residing within the database as
procedures, and other application-specific code running on the application server and interacting
seamlessly with the database. In order to make a call to a database procedure, zxJDBC offers the
callproc() method which takes the name of the procedure to be invoked. In Listing 12-20, we create a
relatively useless procedure and then call it using Jython (Listing 12-21).
Listing 12-20. PostgreSQL Procedure
CREATE OR REPLACE FUNCTION proc_test(
OUT out_parameter CHAR VARYING(25) )
AS $$
DECLARE
BEGIN
SELECT python_implementation
INTO out_parameter
246
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
FROM python_implementations
WHERE id = 1;
RETURN;
END;
$$ LANGUAGE plpgsql;
Listing 12-21. Jython Calling Code
>>> result = cursor.callproc('proc_test')
>>> cursor.fetchall()
[(u'Jython',)]
Although this example was relatively trivial, it is easily to see how the use of database procedures
from zxJDBC could easily become important. Combining database procedures and functions with
application code is a powerful technique, but it does tie an application to a specific database so it should
be used wisely.
Customizing zxJDBC Calls
At times, it is convenient to have the ability to alter or manipulate a SQL statement automatically. This
can be done before the statement is sent to the database, after it is sent to the database, or even just to
obtain information about the statement that has been sent. To manipulate or customize data calls, it is
possible to make use of the DataHandler interface that is available via zxJDBC. There are basically three
different methods for handling type mappings when using DataHandler. They are called at different
times in the process, one when fetching and the other when binding objects for use in a prepared
statement. These datatype mapping callbacks are categorized into four different groups: life cycle,
developer support, binding prepared statements, and building results.
At first mention, customizing and manipulating statements can seem overwhelming and perhaps
even a bit daunting. However, the zxJDBC DataHandler makes this task fairly trivial. Simply create a
handler class and implement the functionality that is required by overriding a given handler method.
What follows is a listing of the various methods that can be overridden, and we’ll look at a simple
example afterward.
Life Cycle
public void preExecute(Statement stmt) throws SQLException;
A callback prior to each execution of the statement. If the statement is a PreparedStatement (created
when parameters are sent to the execute method), all the parameters will have been set.
public void postExecute(Statement stmt) throws SQLException;
A callback after successfully executing the statement. This is particularly useful for cases such as
auto-incrementing columns where the statement knows the inserted value.
Developer Support
public String getMetaDataName(String name);
A callback for determining the proper case of a name used in a DatabaseMetaData method, such as
getTables(). This is particularly useful for Oracle which expects all names to be upper case.
public PyObject getRowId(Statement stmt) throws SQLException;
A callback for returning the row id of the last insert statement.
247
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
Binding Prepared Statements
public Object getJDBCObject(PyObject object, int type);
This method is called when a PreparedStatement is created through use of the execute method.
When the parameters are being bound to the statement, the DataHandler gets a callback to map the
type. This is only called if type bindings are present.
public Object getJDBCObject(PyObject object);
This method is called when no type bindings are present during the execution of a
PreparedStatement.
Building Results
public PyObject getPyObject(ResultSet set, int col, int type);
This method is called upon fetching data from the database. Given the JDBC type, return the
appropriate PyObject subclass from the Java object at column col in the ResultSet set.
Now we’ll examine a simple example of utilizing this technique. The recipe basically follows these steps:
1.
Create a handler class to implement a particular functionality (must
implement the DataHandler interface).
2.
Assign the created handler class to a given cursor object.
3.
Use the cursor object to make database calls.
In Listing 12-22, we override the preExecute method to print a message stating that the functionality
has been altered. As you can see, it is quite easy to do and opens up numerous possibilities.
Listing 12-22. PyHandler.py
from com.ziclix.python.sql import DataHandler
class PyHandler(DataHandler):
def __init__(self, handler):
self.handler = handler
print 'Inside DataHandler'
def getPyObject(self, set, col, datatype):
return self.handler.getPyObject(set, col, datatype)
def getJDBCObject(self, object, datatype):
print "handling prepared statement"
return self.handler.getJDBCObject(object, datatype)
def preExecute(self, stmt):
print "calling pre-execute to alter behavior"
return self.handler.preExecute(stmt)
Jython Interpreter Code
>>> cursor.datahandler = PyHandler(cursor.datahandler)
Inside DataHandler
>>> cursor.execute("insert into test values (?,?)", [1,2])
calling pre-execute
248
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
History
zxJDBC was contributed by Brian Zimmer, one-time lead committer for Jython. This API was written to
enable Jython developers to have the capability of working with databases using techniques that more
closely resembled the Python DB API. The package eventually became part of the Jython distribution
and today it is one of the most important underlying APIs for working with higher level frameworks such
as Django. The zxJDBC API is evolving at the time of this publication, and it is likely to become more
useful in future releases.
Object Relational Mapping
Although zxJDBC certainly offers a viable option for database access via Jython, there are many other
solutions available. Many developers today are choosing to use ORM (Object Relational Mapping)
solutions to work with the database. This section is not an introduction to ORM, we assume that you are
at least a bit familiar with the topic. Furthermore, the ORM solutions that are about to be discussed have
an enormous amount of very good documentation already available either on the web or in book format.
Therefore, this section will give insight on how to use these technologies with Jython, but it will not go
into great detail on how each ORM solution works. With that said, there is no doubt in stating that these
solutions are all very powerful and capable for standalone and enterprise applications alike.
In the next couple of sections, we’ll cover how to use some of the most popular ORM solutions
available today with Jython. You’ll learn how to set up your environment and how to code Jython to work
with each ORM. By the end of this chapter, you should have enough knowledge to begin working with
these ORMs using Jython, and even start building Jython ORM applications.
SqlAlchemy
No doubt about it, SqlAlchemy is one of the most widely known and used ORM solutions for the Python
programming language. It has been around long enough that its maturity and stability make it a great
contender for use in your applications. It is simple to setup, and easy-to-use for both new databases and
legacy databases alike. You can download and install SqlAlchemy and begin using it in a very short
amount of time. The syntax for using this solution is very straight forward, and as with other ORM
technologies, working with database entities occurs via the use of a mapper that links a special Jython
class to a particular table in the database. The overall result is that the application persists through the
use of entity classes as opposed to database SQL transactions.
In this section we will cover the installation and configuration of SqlAlchemy with Jython. The
section will then show you how to get started using it through a few short examples; we will not get into
great detail as there are plenty of excellent references on SqlAlchemy already. However, this section
should fill in the gaps for making use of this great solution on Jython.
Installation
We’ll begin by downloading SqlAlchemy from the web site (www.sqlalchemy.org), at the time of this
writing the version that should be used is 0.6. This version has been installed and tested with the Jython
2.5.0 release. Once you’ve downloaded the package, unzip it to a directory on your workstation and then
traverse to that directory in your terminal or command prompt. Once you are inside of your SqlAlchemy
directory, issue the following command to install:
jython setup.py install
Once you’ve completed this process, SqlAlchemy should be successfully installed into your jython
Libsite-packages directory. You can now access the SqlAlchemy modules from Jython, and you can open
up your terminal and check to ensure that the install was a success by importing sqlalchemy and
checking the version. See Listing 12-23.
249
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
Listing 12-23.
>>> import sqlalchemy
>>> sqlalchemy.__version__
'0.6beta1'
>>>
After we’ve ensured that the installation was a success, it is time to begin working with SqlAlchemy
via the terminal. However, we have one step left before we can begin. Jython uses zxJDBC to implement
the Python database API in Java. The end result is that most of the dialects that are available for use with
SqlAlchemy will not work with Jython out of the box. This is because the dialects need to be rewritten to
implement zxJDBC. At the time of this writing, we could only find one completed dialect, zxoracle, that
was rewritten to use zxJDBC, and we’ll be showing you some examples based upon zxoracle in the next
sections. However, other dialects are in the works including SQL Server and MySQL. The bad news is
that SqlAlchemy will not yet work with every database available, on the other hand, Oracle is a very good
start and implementing a new dialect is not very difficult. You can find the zxoracle.py dialect included
in the source for this book. Browse through it and you will find that it may not be too difficult to
implement a similar dialect for the database of your choice. You can either place zxoracle somewhere on
your Jython path, or place it into the Lib directory in your Jython installation.
Lastly, we will need to ensure that our database JDBC driver is somewhere on our path so that
Jython can access it. Once you’ve performed the procedures included in this section, start up Jython and
practice some basic SqlAlchemy using the information from the next couple of sections.
Using SqlAlchemy
We can work directly with SqlAlchemy via the terminal or command line. There is a relatively basic set of
steps you’ll need to follow in order to work with it. First, import the necessary modules for the tasks you
plan to perform. Second, create an engine to use while accessing your database. Third, create your
database tables if you have not yet done so, and map them to Python classes using a SqlAlchemy
mapper. Lastly, begin to work with the database.
Now there are a couple of different ways to do things in this technology, just like any other. For
instance, you can either follow a very granular process for table creation, class creation, and mapping
that involves separate steps for each, or you can use what is known as a declarative procedure and
perform all of these tasks at the same time. We will show you how to do each of these in this chapter,
along with performing basic database activities using SqlAlchemy. If you are new to SqlAlchemy, we
suggest reading through this section and then going to sqlalchemy.org and reading through some of the
large library of documentation available there. However, if you’re already familiar with SqlAlchemy, you
can move on if you wish because the rest of this section is a basic tutorial of the ORM solution itself.
Our first step is to create an engine that can be used with our database. Once we’ve got an engine
created then we can begin to perform database tasks making use of it. Type the following lines of code
(Listing 12-24) in your terminal, replacing database specific information with the details of your
development database.
Listing 12-24. Creating a Database Engine and Performing Database Tasks
>>> import zxoracle
>>> from sqlalchemy import create_engine
>>> db = create_engine('zxoracle://schema:password@hostname:port/database)
Next, we’ll create the metadata that is necessary to create our database table using SqlAlchemy
(Listing 12-25). You can create one or more tables via metadata, and they are not actually created until
after the metadata is applied to your database engine using a create_all() call on the metadata. In this
250
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
example, we are going to walk you through the creation of a table named Player that will be used in an
application example in the next section.
Listing 12-25. Creating a Database Table
>>>player = Table('player', metadata,
...
Column('id', Integer, primary_key=True),
...
Column('first', String(50)),
...
Column('last', String(50)),
...
Column('position', String(30)))
>>> metadata.create_all(engine)
Our table should now exist in the database and the next step is to create a Python class to use for
accessing this table. See Listing 12-26.
Listing 12-26. Creating a Python Class to Access a Database Table
class Player(object):
def __init__(self, first, last, position):
self.first = first
self.last = last
self.position = position
def __repr__(self):
return "" %(self.first, self.last, self.position)
The next step is to create a mapper to correlate the Player python object and the player database
table. To do this, we use the mapper() function to create a new Mapper object binding the class and
table together (Listing 12-27). The mapper function then stores the object away for future reference.
Listing 12-27. Create a Mapper to Correlate the Python Object and the Database Table
>>> from sqlalchemy.orm import mapper
>>> mapper(Player, player)
Creating the mapper is the last step in the process of setting up the environment to work with our
table. Now, let’s go back and take a quick look at performing all of these steps in an easier way. If we
want to create a table, class, and mapper all at once, then we can do this declaratively. Please note that
with the Oracle dialect, we need to use a sequence to generate the auto-incremented id column for the
table. To do so, import the sqlalchemy.schema.Sequence object and pass it to the id column when
creating. You must ensure that you’ve manually created this sequence in your Oracle database or this
will not work. See Listing 12-28.
Listing 12-28. Creating a Table, Class and Mapper at Once
SQL> create sequence id_seq
2 start with 1
3 increment by 1;
Sequence created.
251
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
# Delarative creation of the table, class, and mapper
>>> from sqlalchemy.ext.declarative import declarative_base
>>> from sqlalchemy.schema import Sequence
>>> Base = declarative_base()
>>> class Player(object):
...
__tablename__ = 'player'
...
id = Column(Integer, Sequence(‘id_seq’), primary_key=True)
...
first = Column(String(50))
...
last = Column(String(50))
...
position = Column(String(30))
...
def __init__(self, first, last, position):
...
self.first = first
...
self.last = last
...
self.position = position
...
def __repr__(self):
...
return "" % (self.first, self.last, self.position)
...
It is time to create a session and begin working with our database. We must create a session class
and bind it to our database engine that was defined with create_engine earlier. Once created, the Session
class will create new session object for our database. The Session class can also do other things that are
out of scope for this section, but you can read more about them at sqlalchemy.org or other great
references available on the web. See Listing 12-29.
Listing 12-29. Creating a Session Class
>>> from sqlalchemy.orm import sessionmaker
>>> Session = sessionmaker(bind=db)
We can start to create Player objects now and save them to our session. The objects will persist in
the database once they are needed; this is also known as a flush(). If we create the object in the session
and then query for it, SqlAlchemy will first persist the object to the database and then perform the query.
See Listing 12-30.
Listing 12-30. Creating and Querying the Player Object
#Import sqlalchemy module and zxoracle
>>> import zxoracle
>>> from sqlalchemy import create_engine
>>> from sqlalchemy import Table, Column, String, Integer, MetaData, ForeignKey
>>> from sqlalchemy.schema import Sequence
# Create engine
>>> db = create_engine('zxoracle://schema:password@hostname:port/database’)
# Create metadata and table
>>> metadata = MetaData()
>>> player = Table('player', metadata,
...
Column('id', Integer, Sequence('id_seq'), primary_key=True),
...
Column('first', String(50)),
...
Column('last', String(50)),
252
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
...
Column('position', String(30)))
>>> metadata.create_all(db)
# Create class to hold table object
>>> class Player(object):
...
def __init__(self, first, last, position):
...
self.first = first
...
self.last = last
...
self.position = position
...
def __repr__(self):
...
return "" % (self.first, self.last, self.position)
# Create mapper to map the table to the class
>>> from sqlalchemy.orm import mapper
>>> mapper(Player, player)
# Create Session class and bind it to the database
>>> from sqlalchemy.orm import sessionmaker
>>> Session = sessionmaker(bind=db)
>>> session = Session()
# Create player objects, add them to the session
>>> player1 = Player('Josh', 'Juneau', 'forward')
>>> player2 = Player('Jim', 'Baker', 'forward')
>>> player3 = Player('Frank', 'Wierzbicki', 'defense')
>>> player4 = Player('Leo', 'Soto', 'defense')
>>> player5 = Player('Vic', 'Ng', 'center')
>>> session.add(player1)
>>> session.add(player2)
>>> session.add(player3)
>>> session.add(player4)
>>> session.add(player5)
# Query the objects
>>> forwards = session.query(Player).filter_by(position='forward').all()
>>> forwards
[, ]
>>> defensemen = session.query(Player).filter_by(position='defense').all()
>>> defensemen
[, ]
>>> center = session.query(Player).filter_by(position='center').all()
>>> center
[]
Well, hopefully from this example you can see the benefits of using SqlAlchemy. Of course, you can
perform all of the necessary SQL actions such as insert, update, select, and delete against the objects.
However, as said before, there are many very good tutorials where you can learn how to do these things.
We’ve barely scratched the surface of what you can do with SqlAlchemy, it is a very powerful tool to add
to any Jython or Python developer’s arsenal.
253
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
Hibernate
Hibernate is a very popular object relational mapping solution used in the Java world. As a matter of fact,
it is so popular that many other ORM solutions are either making use of Hibernate or extending it in
various ways. As Jython developers, we can make use of Hibernate to create powerful hybrid
applications. Because Hibernate works by mapping POJO (plain old Java object) classes to database
tables, we cannot map our Jython objects to it directly. While we could always try to make use of an
object factory to coerce our Jython objects into a format that Hibernate could use, this approach leaves a
bit to be desired. Therefore, if you wish to create an application coded entirely using Jython, this would
probably not be the best ORM solution. However, most Jython developers are used to doing a bit of work
in Java and as such, they can harness the maturity and power of the Hibernate API to create first-class
hybrid applications. This section will show you how to create database persistence objects using
Hibernate and Java, and then use them directly from a Jython application. The end result, code the
entity POJOs in Java, place them into a JAR file along with Hibernate and all required mapping
documents, and then import the JAR into your Jython application and use.
We have found that the easiest way to create such an application is to make use of an IDE such as
Eclipse or Netbeans. Then create two separate projects, one of the projects would be a pure Java
application that will include the entity beans. The other project would be a pure Jython application that
would include everything else. In this situation, you could simply add resulting JAR from your Java
project into the sys.path of your Jython project and you’ll be ready to go. However, this works just as well
if you do not wish to use an IDE.
It is important to note that this section will provide you with one use case for using Jython, Java, and
Hibernate together. There may be many other scenarios in which this combination of technologies
would work out just as well, if not better. It is also good to note that this section will not cover Hibernate
in any great depth; we’ll just scratch the surface of what it is capable of doing. There are a plethora of
great Hibernate tutorials available on the web if you find this solution to be useful.
Entity Classes and Hibernate Configuration
Because our Hibernate entity beans must be coded in Java, most of the Hibernate configuration will
reside in your Java project. Hibernate works in a straightforward manner. You basically map a table to a
POJO and use a configuration file to map the two together. It is also possible to use annotations as
opposed to XML configuration files, but for the purposes of this use case we will show you how to use the
configuration files.
The first configuration file we need to assemble is the hibernate.cfg.xml, which you can find in the
root of your Java project directory tree. The purpose of this file is to define your database connection
information as well as declare which entity configuration files will be used in your project. For the
purposes of this example, we will be using the PostgreSql database, and we’ll be using the classic
examples of the hockey roster application. This makes for a very simple use-case as we only deal with
one table here, the Player table. Hibernate makes it very possible to work with multiple tables and even
associate them in various ways.
Listing 12-31.
org.postgresql.Driver
jdbc:postgresql://localhost/database-name
254
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
username
password
1
org.hibernate.dialect.PostgreSQLDialect
Our next step is to code the plain old Java object for our database table. In this case, we’ll code an
object named Player that contains only four database columns: id, first, last, and position. As you’ll see,
we use standard public accessor methods with private variables in this class.
Listing 12-32.
package org.jythonbook.entity;
public class Player {
public Player(){}
private
private
private
private
long id;
String first;
String last;
String position;
public long getId(){
return this.id;
}
private void setId(long id){
this.id = id;
}
public String getFirst(){
return this.first;
}
public void setFirst(String first){
this.first = first;
}
public String getLast(){
return this.last;
}
public void setLast(String last){
this.last = last;
}
public String getPosition(){
return this.position;
255
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
}
public void setPosition(String position){
this.position = position;
}
}
Lastly, we will create a configuration file that will be used by Hibernate to map our POJO to the
database table itself. We’ll ensure that the primary key value is always populated by using a generator
class type of increment. Hibernate also allows for the use of other generators, including sequences if
desired. The player.hbm.xml file should go into the same package as our POJO, in this case, the
org.jythonbook.entity package.
Listing 12-33. Creating a Hibernate Configuration File
Player for Hockey Team
That is all we have to do inside of the Java project for our simple example. Of course, you can add as
many entity classes as you’d like to your own project. The main point to remember is that all of the
entity classes are coded in Java, and we will code the rest of the application in Jython.
Jython Implementation Using the Java Entity Classes
The remainder of our use-case will be coded in Jython. Although all of the Hibernate configuration files
and entity classes are coded and place within the Java project, we’ll need to import that project into the
Jython project, and also import the Hibernate JAR file so that we can make use of its database session
and transactional utilities to work with the entities. In the case of Netbeans, you’d create a Python
application then set the Python platform to Jython 2.5.0. After that, you should add all of the required
Hibernate JAR files as well as the Java project JAR file to the Python path from within the project
properties. Once you’ve set up the project and taken care of the dependencies, you’re ready to code the
implementation.
256
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
As said previously, for this example we are coding a hockey roster implementation. The application
runs on the command line and basically allows one to add players to a roster, remove players, and check
the current roster. All of the database transactions will make use of the Player entity we coded in our Java
application, and we’ll make use of Hibernate’s transaction management from within our Jython code.
Listing 12-34. Hockey Roster Application Code
from
from
from
from
from
from
from
org.hibernate.cfg import Environment
org.hibernate.cfg import Configuration
org.hibernate import Query
org.hibernate import Session
org.hibernate import SessionFactory
org.hibernate import Transaction
org.jythonbook.entity import Player
class HockeyRoster:
def __init__(self):
self.cfg = Configuration().configure()
self.factory = self.cfg.buildSessionFactory()
def make_selection(self):
'''
Creates a selector for our application. The function prints output to the
command line. It then takes a parameter as keyboard input at the command
line in order to choose our application option.
'''
options_dict = {1:self.add_player,
2:self.print_roster,
3:self.search_roster,
4:self.remove_player}
print "Please chose an option\n"
selection = raw_input('''Press 1 to add a player, 2 to print the roster,
3 to search for a player on the team,
4 to remove player, 5 to quit: ''')
if int(selection) not in options_dict.keys():
if int(selection) == 5:
print "Thanks for using the HockeyRoster application."
else:
print "Not a valid option, please try again\n"
self.make_selection()
else:
func = options_dict[int(selection)]
if func:
func()
else:
print "Thanks for using the HockeyRoster application."
def add_player(self):
'''
Accepts keyboard input to add a player object to the roster list.
257
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
This function creates a new player object each time it is invoked
and inserts a record into the corresponding database table.
'''
addNew = 'Y'
print "Add a player to the roster by providing the following information\n"
while addNew.upper() == 'Y':
first = raw_input("First Name: ")
last = raw_input("Last Name: ")
position = raw_input("Position: ")
id = len(self.return_player_list())
session = self.factory.openSession()
try:
tx = session.beginTransaction()
player = Player()
player.first = first
player.last = last
player.position = position
session.save(player)
tx.commit()
except Exception,e:
if tx!=None:
tx.rollback()
print e
finally:
session.close()
print "Player successfully added to the roster\n"
addNew = raw_input("Add another? (Y or N)")
self.make_selection()
def print_roster(self):
'''
Prints the contents of the Player database table
'''
print "====================\n"
print "Complete Team Roster\n"
print "======================\n\n"
playerList = self.return_player_list()
for player in playerList:
print "%s %s - %s" % (player.first, player.last, player.position)
print "\n"
print "=== End of Roster ===\n"
self.make_selection()
def search_roster(self):
'''
Takes input from the command line for a player's name to search within the
database. If the player is found in the list then an affirmative message
is printed. If not found, then a negative message is printed.
'''
index = 0
found = False
print "Enter a player name below to search the team\n"
first = raw_input("First Name: ")
258
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
last = raw_input("Last Name: ")
position = None
playerList = self.return_player_list()
while index < len(playerList):
player = playerList[index]
if player.first.upper() == first.upper():
if player.last.upper() == last.upper():
found = True
position = player.position
index = index + 1
if found:
print '%s %s is in the roster as %s' % (first, last, position)
else:
print '%s %s is not in the roster.' % (first, last)
self.make_selection()
def remove_player(self):
'''
Removes a designated player from the database
'''
index = 0
found = False
print "Enter a player name below to remove them from the team roster\n"
first = raw_input("First Name: ")
last = raw_input("Last Name: ")
position = None
playerList = self.return_player_list()
found_player = Player()
while index < len(playerList):
player = playerList[index]
if player.first.upper() == first.upper():
if player.last.upper() == last.upper():
found = True
found_player = player
index = index + 1
if found:
print '''%s %s is in the roster as %s,
are you sure you wish to remove?''' % (found_player.first,
found_player.last,
found_player.position)
yesno = raw_input("Y or N")
if yesno.upper() == 'Y':
session = self.factory.openSession()
tx = None
try:
delQuery = "delete from Player player where id = %s" % (found_player.id)
tx = session.beginTransaction()
q = session.createQuery(delQuery)
q.executeUpdate()
tx.commit()
print 'The player has been removed from the roster', found_player.id
except Exception,e:
if tx!=None:
259
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
tx.rollback()
print e
finally:
session.close
else:
print 'The player will not be removed'
else:
print '%s %s is not in the roster.' % (first, last)
self.make_selection()
def return_player_list(self):
'''
Connects to database and retrieves the contents of the
player table
'''
session = self.factory.openSession()
try:
tx = session.beginTransaction()
playerList = session.createQuery("from Player").list()
tx.commit()
except Exception,e:
if tx!=None:
tx.rollback()
print e
finally:
session.close
return playerList
# main
#
# This is the application entry point. It simply prints the application title
# to the command line and then invokes the makeSelection() function.
if __name__ == "__main__":
print "Hockey Roster Application\n\n"
hockey = HockeyRoster()
hockey.make_selection()
We begin our implementation in the main block, where the HockeyRoster class is instantiated. As
you can see, the hibernate configuration is initialized and the session factory is built within the class
initializer. Next, the make_selection() method is invoked which begins the actual execution of the
program. The entire Hibernate configuration resides within the Java project, so we are not working with
XML here, just making use of it. The code then begins to branch so that various tasks can be performed.
In the case of adding a player to the roster, a user could enter the number 1 at the command prompt.
You can see that the addPlayer() function simply creates a new Player object, populates it, and saves it
into the database. Likewise, the searchRoster() function calls another function named returnPlayerList()
which queries the player table using Hibernate query language and returns a list of Player objects.
In the end, we have a completely scalable solution. We can code our entities using a mature and
widely used Java ORM solution, and then implement the rest of the application in Jython. This allows us
to make use of the best features of the Python language, but at the same time, persist our data using Java.
260
www.it-ebooks.info
CHAPTER 12 ■ DATABASES AND JYTHON: OBJECT RELATIONAL MAPPING AND USING JDBC
Summary
You would be hard-pressed to find too many enterprise-level applications today that do not make use of
a relational database in one form or another. The majority of applications in use today use databases to
store information as they help to provide robust solutions. That being said, the topics covered in this
chapter are very important to any developer. In this chapter, we learned that there are many different
ways to implement database applications in Jython, specifically through the Java database connectivity
API or an object relational mapping solution.
261
www.it-ebooks.info
www.it-ebooks.info
C H A P T E R 13
■■■
P A R T
III
■■■
Developing Applications
with Jython
263
www.it-ebooks.info
CHAPTER 13 ■ SIMPLE WEB APPLICATIONS
264
www.it-ebooks.info
C H A P T E R 13
■■■
Simple Web Applications
One of the major benefits of using Jython is the ability to make use of Java platform capabilities
programming in the Python programming language instead of Java. In the Java world today, the most
widely used web development technique is the Java servlet. Now in JavaEE, there are techniques and
frameworks used so that we can essentially code HTML or other markup languages as opposed to
writing pure Java servlets. However, sometimes writing a pure Java servlet still has its advantages. We
can use Jython to write servlets and this adds many more advantages above and beyond what Java has to
offer because now we can make use of Python language features as well. Similarly, we can code web start
applications using Jython instead of pure Java to make our lives easier. Coding these applications in pure
Java has proven sometimes to be a difficult and sometimes grueling task. We can use some of the
techniques available in Jython to make our lives easier. We can even code WSGI applications with Jython
making use of the modjy integration in the Jython project.
In this chapter, we will cover three techniques for coding simple web applications using Jython:
servlets, web start, and WSGI. We’ll get into details on using each of these different techniques here, but
we will discuss deployment of such solutions in Chapter 17.
Servlets
Servlets are a Java platform technology for building web-based applications. They are a platform- and
server-independent technology for serving content to the web. If you are unfamiliar with Java servlets, it
would be worthwhile to learn more about them. An excellent resource is wikipedia
(http://en.wikipedia.org/wiki/Java_Servlet); however, there are a number of other great places to find
out more about Java servlets. Writing servlets in Jython is a very productive and easy way to make use of
Jython within a web application. Java servlets are rarely written using straight Java anymore. Most Java
developers make use of Java Server Pages (JSP), Java Server Faces (JSF), or some other framework so that
they can use a markup language to work with web content as opposed to only working with Java code.
However, in some cases it is still quite useful to use a pure Java servlet. For these cases we can make our
lives easier by using Jython instead. There are also great use-cases for JSP; similarly, we can use Jython
for implementing the logic in our JSP code. The latter technique allows us to apply a model-viewcontroller (MVC) paradigm to our programming model, where we separate our front-end markup from
any implementation logic. Either technique is rather easy to implement, and you can even add this
functionality to any existing Java web application without any trouble.
Another feature offered to us by Jython servlet usage is dynamic testing. Because Jython compiles at
runtime, we can make code changes on the fly without recompiling and redeploying our web
application. This can make it very easy to test web applications, because usually the most painful part of
web application development is the wait time between deployment to the servlet container and testing.
265
www.it-ebooks.info
CHAPTER 13 ■ SIMPLE WEB APPLICATIONS
Configuring Your Web Application for Jython Servlets
Very little needs to be done in any web application to make it compatible for use with Jython servlets.
Jython contains a built-in class named PyServlet that facilitates the creation of Java servlets using Jython
source files. We can make use of PyServlet quite easily in our application by adding the necessary XML
configuration into the application’s web.xml descriptor such that the PyServlet class gets loaded at
runtime and any file that contains the .py suffix will be passed to it. Once this configuration has been
added to a web application, and jython.jar has been added to the CLASSPATH then the web application
is ready to use Jython servlets. See Listing 13-1.
Listing 13-1. Making a Web Application Compatible with Jython
PyServlet
org.python.util.PyServlet
1
PyServlet
*.py
Any servlet that is going to be used by a Java servlet container also needs to be added to the web.xml
file as well, since this allows for the correct mapping of the servlet via the URL. For the purposes of this
book, we will code a servlet named NewJythonServlet in the next section, so the following XML
configuration will need to be added to the web.xml file. See Listing 13-2.
Listing 13-2. Coding a Jython Servlet
NewJythonServlet
NewJythonServlet
NewJythonServlet
/NewJythonServlet
Writing a Simple Servlet
In order to write a servlet, we must have the javax.servlet.http.HttpServlet abstract Java class within our
CLASSPATH so that it can be extended by our Jython servlet to help facilitate the code. This abstract
class, along with the other servlet implementation classes, is part of the servlet-api.jar file. According to
the abstract class, there are two methods that we should override in any Java servlet, those being doGet
and doPost. The former performs the HTTP GET operation while the latter performs the HTTP POST
operation for a servlet. Other commonly overridden methods include doPut, doDelete, and
getServletInfo. The first performs the HTTP PUT operation, the second performs the HTTP DELETE
operation, and the last provides a description for a servlet. In the following example, and in most usecases, only the doGet and doPost are used.
266
www.it-ebooks.info
CHAPTER 13 ■ SIMPLE WEB APPLICATIONS
Let’s first show the code for an extremely simple Java servlet. This servlet contains no functionality
other than printing its name along with its location in the web application to the screen. Following that
code we will take a look at the same servlet coded in Jython for comparison (Listing 13-3).
Listing 13-3. NewJavaServlet.java
import
import
import
import
import
import
java.io.IOException;
java.io.PrintWriter;
javax.servlet.ServletException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
public class NewJavaServlet extends HttpServlet {
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("");
out.println("");
out.println("Servlet NewJavaServlet Test ");
out.println("");
out.println("");
out.println("Servlet NewJavaServlet at " + request.getContextPath () +
"
");
out.println("");
out.println("");
} finally {
out.close();
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
public String getServletInfo() {
return "Short description";
}
267
www.it-ebooks.info
CHAPTER 13 ■ SIMPLE WEB APPLICATIONS
}
All commenting has been removed from the code in an attempt to make the code a bit shorter. Now,
Listing 13-4 is the equivalent servlet code written in Jython.
Listing 13-4.
from javax.servlet.http import HttpServlet
class NewJythonServlet (HttpServlet):
def doGet(self,request,response):
self.doPost (request,response)
def doPost(self,request,response):
toClient = response.getWriter()
response.setContentType ("text/html")
toClient.println ("Jython Servlet Test " +
"Servlet Jython Servlet at" +
request.getContextPath() +
"
")
def getServletInfo(self):
return "Short Description"
Not only is the concise code an attractive feature, but also the easy development lifecycle for
working with dynamic servlets. As stated previously, there is no need to redeploy each time you make a
change because of the compile at runtime that Jython offers. Simply change the Jython servlet, save, and
reload the webpage to see the update. If you begin to think about the possibilities you’ll realize that the
code above is just a basic example, you can do anything in a Jython servlet that you can with Java and
even most of what can be done using the Python language as well.
To summarize the use of Jython servlets, you simply include jython.jar and servlet-api.jar in your
CLASSPATH. Add necessary XML to the web.xml, and then finally code the servlet by extending the
javax.servlet.http.HttpServlet abstract class.
Using JSP with Jython
Harnessing Jython servlets allows for a more productive development lifecycle, but in certain situations
Jython code may not be the most convenient way to deal with front-facing web code. Sometimes using a
markup language such as HTML works better for developing sophisticated front-ends. For instance, it is
easy enough to include JavaScript code within a Jython servlet. However, all of the JavaScript code would
be written within the context of a String. Not only does this eliminate the usefulness of an IDE for
situations such as semantic code coloring and auto completion, but it also makes code harder to read
and understand. Cleanly separating such code from Jython or Java makes code more clear to read, and
easier to maintain in the long run. One possible solution would be to choose from one of the Python
template languages such as Django, but using Java Server Pages (JSP) technology can also be a nice
solution.
Using a JSP allows one to integrate Java code into HTML markup in order to generate dynamic page
content. We are not fans of JSP. There, we said it: JSP can make code a living nightmare if the technology
is not used correctly. Although JSP can make it very easy to mix JavaScript, HTML, and Java into one file,
it can make maintenance very difficult. Mixing Java code with HTML or JavaScript is a bad idea. The
same would also be true for mixing Jython and HTML or JavaScript.
268
www.it-ebooks.info
CHAPTER 13 ■ SIMPLE WEB APPLICATIONS
The Model-View-Controller (MVC) paradigm allows for clean separation between logic code, such
as Java or Jython, and markup code such as HTML. JavaScript is always gets grouped into the same arena
as HTML because it is a client-side scripting language. In other words, JavaScript code should also be
separated from the logic code. In thinking about MVC, the controller code would be the markup and
JavaScript code used to capture data from the end-user. Model code would be the business logic that
manipulates the data. Model code is contained within our Jython or Java. The view would be the markup
and JavaScript displaying the result.
Clean separation using MVC can be achieved successfully by combining JSP with Jython servlets. In
this section we will take a look at a simple example of how to do so. As with many of the other examples
in this text it will only brush upon the surface of great features that are available. Once you learn how to
make use of JSP and Jython servlets you can explore further into the technology.
Configuring for JSP
There is no real configuration above and beyond that of configuring a web application to make use of
Jython servlets. Add the necessary XML to the web.xml deployment descriptor, include the correct JARs
in your application, and begin coding. What is important to note is that the .py files that will be used for
the Jython servlets must reside within your CLASSPATH. It is common for the Jython servlets to reside in
the same directory as the JSP web pages themselves. This can make things easier, but it can also be
frowned upon because this concept does not make use of packages for organizing code. For simplicity
sake, we will place the servlet code into the same directory as the JSP, but you can do it differently.
Coding the Controller/View
The view portion of the application will be coded using markup and JavaScript code. Obviously, this
technique utilizes JSP to contain the markup, and the JavaScript can either be embedded directly into
the JSP or reside in separate .js files as needed. The latter is the preferred method in order to make things
clean, but many web applications embed small amounts of JavaScript within the pages themselves.
The JSP in this example is rather simple, there is no JavaScript in the example and it only contains a
couple of input text areas. This JSP will include two forms because we will have two separate submit
buttons on the page. Each of these forms will redirect to a different Jython servlet, which will do
something with the data that has been supplied within the input text. In our example, the first form
contains a small textbox in which the user can type any text that will be redisplayed on the page once the
corresponding submit button has been pressed. Very cool, eh? Not really, but it is of good value for
learning the correlation between JSP and the servlet implementation. The second form contains two text
boxes in which the user will place numbers; hitting the submit button in this form will cause the
numbers to be passed to another servlet that will calculate and return the sum of the two numbers.
Listing 13-5 is the code for this simple JSP.
Listing 13-5. JSP Code for a Simple Controller/Viewer Application
*testJSP.jsp*
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
269
www.it-ebooks.info
CHAPTER 13 ■ SIMPLE WEB APPLICATIONS
Jython JSP Test
${page_text}
In this JSP example, you can see that the first form redirects to a Jython servlet named
add_to_page.py, which plays the role of the controller. In this case, the text that is contained within the
input textbox named p will be passed into the servlet, and redisplayed in on the page. The text to be
redisplayed will be stored in an attribute named page_text, and you can see that it is referenced within
the JSP page using the ${} notation. Listing 13-6 is the code for add_to_page.py.
Listing 13-6. A Simple Jython Controller Servlet
#######################################################################
# add_to_page.py
#
# Simple servlet that takes some text from a web page and redisplays
# it.
#######################################################################
import java, javax, sys
class add_to_page(javax.servlet.http.HttpServlet):
def doGet(self, request, response):
self.doPost(request, response)
def doPost(self, request, response):
addtext = request.getParameter("p")
if not addtext:
addtext = ""
270
www.it-ebooks.info
CHAPTER 13 ■ SIMPLE WEB APPLICATIONS
request.setAttribute("page_text", addtext)
dispatcher = request.getRequestDispatcher("testJython.jsp")
dispatcher.forward(request, response)
Quick and simple, the servlet takes the request and obtains value contained within the parameter p.
It then assigns that value to a variable named addtext. This variable is then assigned to an attribute in the
request named page_text and forwarded back to the testJython.jsp page. The code could just as easily
have forwarded to a different JSP, which is how we’d go about creating a more in-depth application.
The second form in our JSP takes two values and returns the resulting sum to the page. If someone
were to enter text instead of numerical values into the text boxes then an error message would be
displayed in place of the sum. While very simplistic, this servlet demonstrates that any business logic can
be coded in the servlet, including database calls, and so on. See Listing 13-7.
Listing 13-7. Jython Servlet Business Logic
#######################################################################
# add_numbers.py
#
# Calculates the sum for two numbers and returns it.
#######################################################################
import javax
class add_numbers(javax.servlet.http.HttpServlet):
def doGet(self, request, response):
self.doPost(request, response)
def doPost(self, request, response):
x = request.getParameter("x")
y = request.getParameter("y")
if not x or not y:
sum = "You must place numbers in each value box"
else:
try:
sum = int(x) + int(y)
except ValueError, e:
sum = "You must place numbers only in each value
box"
request.setAttribute("sum", sum)
dispatcher = request.getRequestDispatcher("testJython.jsp")
dispatcher.forward(request, response)
If we add the JSP and the servlets to the web application we created in the previous Jython Servlet
section, then this example should work out-of-the-box.
It is also possible to embed code into Java Server Pages by using various template tags known as
scriptlets to enclose the code. In such cases, the JSP must contain Java code unless a special framework
such as the Bean Scripting Framework (http://jakarta.apache.org/bsf/) is used along with JSP. For more
271
www.it-ebooks.info
CHAPTER 13 ■ SIMPLE WEB APPLICATIONS
details on using Java Server Pages, please take a look at the Sun Microsystems JSP documentation
(http://java.sun.com/products/jsp/docs.html) or pick up a book such as Beginning JSP, JSF and Tomcat
Web Development: From Novice to Professional from Apress.
Applets and Java Web Start
At the time of this writing, applets in Jython 2.5.0 are not yet an available option. This is because applets
must be statically compiled and available for embedding within a webpage using the Source Exif Data:
File Type : PDF
File Type Extension : pdf
MIME Type : application/pdf
PDF Version : 1.6
Linearized : No
Create Date : 2010:02:11 10:40:21-05:00
Creator : Adobe InDesign CS4 (6.0)
Modify Date : 2012:11:26 22:57:06+04:00
Www It-ebooks Info : {0C23F91E-8B0B-458C-831D-C7768D737A44}
Has XFA : No
Tagged PDF : No
XMP Toolkit : Adobe XMP Core 5.2-c001 63.139439, 2010/09/27-13:37:26
Metadata Date : 2012:11:21 12:20:46-02:00
Creator Tool : Adobe InDesign CS4 (6.0)
Format : application/pdf
Document ID : uuid:92ff2e65-aeae-4424-bb38-6dd6576099cc
Instance ID : uuid:04782079-218e-4ae1-92ef-5e4f53cdf69e
Producer : Adobe PDF Library 9.0
Page Count : 545
EXIF Metadata provided by EXIF.tools