JythonBook / chapter3.rst

Josh Juneau d9b2bb8 

Chapter 3: Operators, Expressions, and Program Flow

Up until this point, we’ve have not yet covered the different means of writing expressions in Python.  The focus of this chapter is to go in depth on each of the ways we can evaluate code, and write meaningful blocks of conditional logic.  We’ll cover the details of each operator that can be used in Python expressions.  This chapter will also cover some topics that have already been discussed in more meaningful detail.

We will begin by discussing details of expressions.  We have already seen some expressions in use while reading through the previous chapters.  Here we will 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.

Types of Expressions

An expression in Python is a block 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.

This chapter will go into detail on how you write and evaluate mathematical expressions, boolean expressions, and augmented assignments.  

Mathematical Operations

The Python language of course contains all of your basic mathematical operations.  This section will briefly touch upon each operator that is available for use in Python and how they function.  You will also learn about a few built-in functions which can be used to assist in  your mathematical expressions.  Finally, you’ll see how to use conditionals in the Python language and learn order of evaluation.

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.

Operator    Description  
'+'           Addition                        
'-'           Subtraction                     
'*'           Multiplication                  
/           Division                        
//          Truncating Division             
%           Modulo (Remainder of Division)  
**          Power Operator                  
+var        Unary Plus                      
-var        Unary Minus                     

Table 3-1:  Numeric Operators

Most of the operators in the table above are easily understood.  However, the truncating division, modulo, power, and unary operators could use some explanation.  Truncating division will automatically truncate a division result into an integer.  Modulo will return the remainder of a 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.  Unary plus and unary minus are used to evaluate positive or negative numbers.  The following set of examples will help to clarify these topics. ::

	# Performing basic mathematical computations

	>>> 10 - 6
	>>> 9 * 7
	>>> 9 / 3
	>>> 10 / 3
	>>> 10 // 3
	>>> 3.14 / 2
	>>> 3.14 // 2
	>>> 36 / 5
	>>> 36 % 5
	>>> 5**2
	>>> 100**2
	>>> -10 + 5
	>>> +5 - 5

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 an integer or the floor 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 incorrect 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 when using the // operator.  Since this is going to be the standard in future releases, it is best practice to import from __future__ when performing division in Jython 2.5. ::

	>>> from __future__ import division
	>>> 9/5
	>>> 9/4
	>>> 9/3
	>>> 9//3
	>>> 9//5

As stated at the beginning of the section, there are a number of built-in mathematical functions that are at your disposal.  

Function           Description                                                    
abs(var)           Absolute value  
pow(x, y)          Used in place of power operator                                   
pow(x,y,modulo)    Ternary power-modulo                                           
round(var[, n])    Returns a value rounded to the nearest 10-n                    
divmod(x, y)       Returns both the quotient and remainder of division operation  

Table 3-2:  Mathematical Built-in functions ::

	#  The following code provides some examples for using mathematical built-ins
	>>> abs(9)
	>>> abs(-9)
	>>> divmod(8,4)
	(2, 0)
	>>> pow(8,2)
	>>> pow(8,2,3)
	>>> round(5.67,1)
	>>> round(5.67)

The bitwise and logical operators as well as the conditional operators can be used to combine and compare logic.  As with the mathematical operators described above, these operators have no significant difference to that of Java.

Operator    Description  
>                          Greater than           
<                          Less than              
>=                         Greater than or equal  
<=                         Less than or equal     
!=                         Not equal              
==                         Equal                  
&                          Bitwise and            
|                          Bitwise or             
^                          Bitwise xor            
~                          Bitwise negation       
<<                         Shift left             
>>                         Shift right            

Table 3-3: Bitwise and Conditional Operators

Augmented assignment operators are those that combine two or more operations into one.  While augmented assignment can assist in coding concisely, some say that too many such operators can make code more difficult to read.

Operator    Description and Logic  
+=                                   a = a + b   
-=                                   a = a – b   
*=                                   a = a * b   
/=                                   a = a / b   
%=                                   a = a % b   
//=                                  a = a // b  
**=                                  a = a** b   
&=                                   a = a & b   
|=                                   a = a | b   
^=                                   a = a ^ b   
>>=                                  a = a >> b  
<<=                                  a = a << b 

Table 3-4:  Augmented Assignment Operators

Boolean Expressions

Comparing 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.

Conditional    Logic  
and                     In an *x and y* evaluation, both x and y must evaluate to True   
or                      In an *x or y* evaluation, if x is false then y is evaluated.    
not                     In a *not x* evaluation, if *not x*, we mean the opposite of x   

Table 3-5: Boolean Conditionals


There are a number of conversion functions built into the language in order to help conversion of one data type to another.  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.  

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                            
float(value)             Converts to float                                                                                      
frozenset(set)           Converts a set into a frozen set                                                                       
hex(value)               Converts an integer into a hex string                                                                  
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 integer to octal                                                                              
ord(value)               Converts a character into it’s integer value                                                           
repr(value)              Converts object into an expression string.  Same as enclosing expression in reverse quotes ( `x + y`)  
set(sequence)            Converts a sequence into a set                                                                         
str(value)               Converts an object into a string                                                                       
tuple(sequence)          Converts a given sequence to a tuple                                                                   
unichr(value)            Converts integer to a Unicode character                                                                

Table 3-6:  Conversion Functions

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. ::

	# Suppose keyboard input contains an expression in string format (x * y)
	>>> x = 5
	>>> y = 12
	>>> keyboardInput = 'x * y'
	>>> eval(keyboardInput)

Program Flow

The Python programming language has structure that sets it apart from the others.  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.  In order to develop a statement in Python, you must adhere to proper spacing techniques throughout the code block.  Convention and good practice adhere to four spaces of indentation per statement throughout the entire program.  Follow this convention along with some control flow and you’re sure to develop some easily maintainable software.

The standard Python if-else conditional statement is used in order to evaluate expressions and branch program logic based upon the outcome.  Expressions that are usable in an if-else statement can consist of any operators 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-else* statement follows one path if an expression evaluates to *True*, or a different path if it evaluates to *False.*  

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. ::

	# terminal symbols are left out of this example so that you can see the concise 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’
	    print ‘The number is less than pi’

Another construct that we touched upon in Chapter 1 was the loop.  Every programming language provides looping implementations, and Python is no different.  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 loop will continue processing until the expression evaluates to *False*.  At this time the looping ends and that would be it for the Java implementation.  However, in Python the *while * loop construct also contains an *else* clause which is executed when the looping completes. ::

	while True:
	    # perform some processing
	    print ‘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.  Also mentioned in Chapter 1 were the *break*, and *continue* statements.  These all come in handy when using any looping construct.  The *break* statement can be used to break out of a loop.  It should be noted that if there are nested loops then the *break* statement will break out of the inner-most loop only, the outer loops will continue to process.  The *continue* statement can be used to break out of the current processing statement and continue the loop from the beginning.  The *continue* can be thought of as a skipping statement as it will cause execution to skip all remaining statements in the block and restart from the beginning (if the loop expression still evaluates to *True* of course). ::

	while x != y:
	    # perform some processing
	    if x < 0:
	    print ‘The program executed to completion’

In the example above, the program will continue to process until x does not equal y.  However, if at any point during the processing the x variable evaluates less than zero, then the execution stops.  The *else* clause will not be executed if the *break* statement is invoked.  It will only be executed under normal termination of the 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.  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. ::

	for(x = 0; x <= myList.size(); x++){
	    // processing statements iterating through myList
	    System.out.println(“The current index is: “ + x);

	x = 0
	for value in myList:
	    # processing statements using value as the current item in myList
	    print ‘The current index is %i’ % (x)
	    x = x + 1

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. ::

	>>> myList = ['jython','java','python','jruby','groovy']
	>>> for index, value in enumerate(myList):
	...     print index, value
	0 jython
	1 java
	2 python
	3 jruby
	4 groovy

Now we have covered the program flow for conditionals and looping constructs in the Python language.  Note that you can next to any level, and provide as many *if-else* conditionals as you’d like.  However, good programming practice will tell you to keep it as simple as possible or the logic will become too hard to follow.  

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 utiliation of the *raw_input()* function. ::

	playerDict = {}
	saveFile = False
	exitSystem = False    
	# Enter a loop to enter inforation from keyboard
	while not exitSystem:    
	    print 'Sports Team Administration App'
	    enterPlayer = 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) ")
	    if enterPlayer.upper() == 'C': 
	        exitSystem = False        
	    # Enter a player for the team
	        print 'Enter a list of players on our team along with their position'
	        enterCont = 'Y'
	        #  While continuing to enter new players, perform the following
	        while enterCont.upper() == 'Y':
	            name = raw_input('Enter players first name: ')
	            position = raw_input('Enter players position: ')
	            playerDict[name] = position
	            saveFile = True
	            enterCont = raw_input("Enter another player? (Press 'N' to exit or 'Y' to continue)")
	            exitSystem = True 
	   elif enterPlayer.upper() == 'M':
	        exitSystem = False
	        # Read values from the external file into a dictionary object
	        print '\n’
	       print 'Manage the Team'
	        playerfile = open('players.txt','r')
	        for player in playerfile:
	            playerList = player.split(':')
	            playerDict[playerList[0]] = playerList[1]
	        print 'Team Listing' 
	        print '++++++++++++'
	        for i, player in enumerate(playerDict):
	            print 'Player %s Name: %s -- Position: %s' %(i, player, playerDict[player])
	        exitSystem = True
	    # Save the external file and close resources
	    if saveFile:
	        print 'Saving Team Data...'
	        playerfile = open('players.txt','w')
	        for player in playerDict:
	            playerfile.write(player + ':' + playerDict[player] + '\n')


All programs are constructed out of definitions, 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.