1. introduction to python 1.1 versions 2 and 3 - … · the two other ide's that i have...

34
CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4) 1. Introduction to Python Official Python website: http://www.python.org Python download (most recent version is 3.5.2): https://www.python.org/downloads Python v3.5 documentation: https://docs.python.org/3 Python v3.5 tutorial: https://docs.python.org/3/tutorial/index.html Python v3.5 standard library: https://docs.python.org/3/library/index.html#library-index Python v3.5 language reference: https://docs.python.org/3/reference/index.html#reference-index Python package index: https://pypi.python.org/pypi 1.1 Versions 2 and 3 There are two major versions of Python, versions 2.7 and 3. There are a few significant differences between these two ver - sions and v3 is not backwards-compatible with v2. New development on the v2 branch has effectively terminated, and v3 (the most recent version is 3.6.0) is said to be the future of the Python language. Consequently, my opinion is that if you are new to Python then you might as well learn v3 because v2 code will eventually be obsoleted. See reference [1] below for more discussion of the changes. The major difference between v2 and v3 that impacts the programs we will be writing is that in v2, print was a statement but in v3 it is a built-in function (built-in functions are commonly used functions that are directly implemented by the Python interpreter and do not require an import statement to access the function). For example, # Version 2 Hello World Program # Version 3 Hello World Program print "Hello world.\n" print("Hello world.\n") By the way, there are a lot of tutorials and discussions about Python on the internet. Much of the published Python code is v2 and not v3, so be aware of that. Another v3 change that might impact us is how the division operator works with integer operands. In particular, in v2 , print 3/4 prints 0 because invoking / on two integer operands results in an integer quotient. In v3, print(3/4) prints 0.75 (floating point division is performed) and to perform integer division use print(3//4) which prints 0. Another v3 change concerns rounding. In v2, positive numbers are rounded up, negative numbers are rounded to negative infinity, i.e., round(1.5) is 2, round(2.5) is 3, round(-1.5) is -2.0, round(-2.5) is -3.0. In v3, numbers ending in .5 are are rounded to the nearest even number: round(1.5) is 2, round(2.5) is 2, round(-1.5) is -2.0, and round(-2.5) is -2.0. Other changes in v3 can be found at [1, 2]. References 1. Wiki.Python.Org - Python v2 or v3: https://wiki.python.org/moin/Python2orPython3 2. Python.org - What's new in Python 3.0? https://docs.python.org/3/whatsnew/3.0.html 1.2 Online Development There are several online development websites which provide IDE's that run from simple to sophisticated. The primary advantage of using an online IDE is that you do not have to install software on your computer, you just log in and start coding. I placed links on the course website to several online IDE's. I do not have significant experience with any of these, but when playing around with them, I liked the looks of Coding Ground (mainly because it looks "clean" and provides a Linux Bash shell interface). Some of these IDE's require you to create an account to log in. They are all free or commercial products which also offer a free evaluation environment. The Learn Python environment allows you edit and run your code online and also provides a number of tutorials to help you learn Python. Be aware that the Learn Python tutorials do not go deep into each topic. If you are looking for a good Python tutorial, I have listed several in the section named Python References (Tutorials, Books) on the course webpage. The Python Tutor website is interesting as it permits you to enter Python code and then execute it, line by line, while the tool displays a visualization of the program variables and their changing values. (c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 1

Upload: phamtu

Post on 27-Sep-2018

218 views

Category:

Documents


0 download

TRANSCRIPT

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

1. Introduction to PythonOfficial Python website: http://www.python.orgPython download (most recent version is 3.5.2): https://www.python.org/downloadsPython v3.5 documentation: https://docs.python.org/3Python v3.5 tutorial: https://docs.python.org/3/tutorial/index.htmlPython v3.5 standard library: https://docs.python.org/3/library/index.html#library-indexPython v3.5 language reference: https://docs.python.org/3/reference/index.html#reference-indexPython package index: https://pypi.python.org/pypi

1.1 Versions 2 and 3There are two major versions of Python, versions 2.7 and 3. There are a few significant differences between these two ver -sions and v3 is not backwards-compatible with v2. New development on the v2 branch has effectively terminated, and v3(the most recent version is 3.6.0) is said to be the future of the Python language. Consequently, my opinion is that if youare new to Python then you might as well learn v3 because v2 code will eventually be obsoleted. See reference [1] belowfor more discussion of the changes.

The major difference between v2 and v3 that impacts the programs we will be writing is that in v2, print was a statementbut in v3 it is a built-in function (built-in functions are commonly used functions that are directly implemented by thePython interpreter and do not require an import statement to access the function). For example,

# Version 2 Hello World Program # Version 3 Hello World Programprint "Hello world.\n" print("Hello world.\n")

By the way, there are a lot of tutorials and discussions about Python on the internet. Much of the published Python codeis v2 and not v3, so be aware of that.

Another v3 change that might impact us is how the division operator works with integer operands. In particular, in v2 ,print 3/4 prints 0 because invoking / on two integer operands results in an integer quotient. In v3, print(3/4) prints0.75 (floating point division is performed) and to perform integer division use print(3//4) which prints 0.

Another v3 change concerns rounding. In v2, positive numbers are rounded up, negative numbers are rounded to negativeinfinity, i.e., round(1.5) is 2, round(2.5) is 3, round(-1.5) is -2.0, round(-2.5) is -3.0. In v3, numbers ending in .5 are arerounded to the nearest even number: round(1.5) is 2, round(2.5) is 2, round(-1.5) is -2.0, and round(-2.5) is -2.0.

Other changes in v3 can be found at [1, 2].

References1. Wiki.Python.Org - Python v2 or v3: https://wiki.python.org/moin/Python2orPython32. Python.org - What's new in Python 3.0? https://docs.python.org/3/whatsnew/3.0.html

1.2 Online DevelopmentThere are several online development websites which provide IDE's that run from simple to sophisticated. The primaryadvantage of using an online IDE is that you do not have to install software on your computer, you just log in and startcoding. I placed links on the course website to several online IDE's. I do not have significant experience with any of these,but when playing around with them, I liked the looks of Coding Ground (mainly because it looks "clean" and provides aLinux Bash shell interface). Some of these IDE's require you to create an account to log in. They are all free or commercialproducts which also offer a free evaluation environment. The Learn Python environment allows you edit and run your codeonline and also provides a number of tutorials to help you learn Python. Be aware that the Learn Python tutorials do notgo deep into each topic. If you are looking for a good Python tutorial, I have listed several in the section named PythonReferences (Tutorials, Books) on the course webpage. The Python Tutor website is interesting as it permits you to enterPython code and then execute it, line by line, while the tool displays a visualization of the program variables and theirchanging values.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 1

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

1.3 Offline DevelopmentThere are numerous IDE's that support Python programming. The page at [1] lists many of them. IDLE is the officialPython IDE which is also installed when you install Python3. IDLE is not as full-featured as many of the other IDE's butit is more than sufficient and easy to use when writing small programs. It is the IDE that I have been using on my Linuxsystem. The two other IDE's that I have experience with are Eclipse (with the PyDev plugin) and NetBeans. Both IDE'sare written in Java so they can be easily installed and executed on OS X, Linux, and Windows. The other IDE I haveplayed around with is PyCharm, which on the surface looks nice and is highly customizable (as are many IDE's). Earlierthis year, I decided that I would start using PyCharm as my Python IDE. After installing it and spending quite a bit oftime configuring it, I concluded that it seems to be very buggy. I have not given up on it yet and time will tell me whetheris it worthwhile to use PyCharm or to throw it in the trash.

References1. Python.Org Wiki - IDE's: https://wiki.python.org/moin/IntegratedDevelopmentEnvironments

2. The Python InterpreterPython is an interpreted dynamically-typed language1. The python interpreter implements a read, evaluate, print loop(REPL) where it continuously loops reading input, evaluating/executing the input, and printing the result of the evalua-tion.

The Python interpreter on Linux is invoked with the python or python3 command (when both Python v2 and v3 areinstalled; if only Python 3 is installed you would type either python or python3; the version in used can be determinedby invoking python --version). Because Python is interpreted, we do not have to write a complete program to try thingsout, e.g.,

>>> print("Hello world.") The default interpreter prompt is >>>. I read that this can be changed somehow.Hello world.>>> 2 + 35

>>> x = 5 ; y = 10 ; z = x + y Multiple statements on the same line are separated by semicolons.>>> z To display the value of a variable, just type the name of the variable.15

Dynamically-typed languages are those in which the type of a variable (or object) can change during execution. Generally,dynamically-typed programming languages do not require the programmer to specify data types for variables, constants,and so on. Python does not, so the following code is perfectly legal (note that Python statements on the same line are sep-arated by a semicolon). type(x) is a built-in function that returns the type of x as a string.

# dynamic.py - dynamic typing example.x = 10 ; print("x =", x, "the type of x is", type(x))x = 3.14159 ; print("x =", x, "the type of x is", type(x))x = "Günther is loose again. Release the hounds." ; print("x =", x, "the type of x is", type(x))

$ python3 dynamic.pyx = 10 the type of x is <class 'int'>x = 314159 the type of x is <class 'float'>x = "Günther is loose again. Release the hounds." the type of x is <class 'str'>

A compiler translates high-level language code into low-level machine language code which is directly executed by theCPU. Most interpreted languages are compiled into an internal "bytecode" format which is then executed (or interpreted)by a virtual machine. Python source code files generally have a .py extension. If you find .pyc files in a directory, those arePython files that have been compiled into bytecodes.

1 In programming language terms, static generally refers to something that happens at compile-time. The term dynamic refers to something that happens atrun-time.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 2

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

3. Language FeaturesThere are thousands of Python tutorials and blog posts. A few of what I think are decent Python tutorials are,

1. Think Python: How to think like a computer scientist, 2nd Ed, by Allen Downey2. Problem Solving using Python by Brad Miller and David Ranum3. Python Tutorial by TutorialsPoint.com

Note that Python is case-sensitive.

3.1 CommentsA single-line comment begins with # and extends to the end of line (this is similar to how // works in C++ and Java).Multi-line comments may be written as several lines, each starting with #, or the comment can be embedded within triplequotes, e.g.,

# SomeFile.py## Description# Blah blah blah yakkity blah blah. Blah blah blah yakkity blah blah. # Blah blah blah yakkity blah blah. Blah blah blah yakkity blah blah.

def main():"""This is a multi-line comment embedded within triple quotes. This is a multi-line commentembedded within triple quotes. This is a multi-line comment embedded within triple quotes. embedded within triple quotes. This is a multi-line comment embedded within triple quotes. embedded within triple quotes. This is a multi-line comment embedded within triple quotes. """

A Python docstring is a string literal """...""" that appears as the first statement in a function. See [1] for more informa-tion regarding docstrings. The job of a docstring is to provide a relatively brief description of what the function does. Forexample,

# fact()def fact(n):

""" Return n! """if n < 2:

return 1else:

return n * fact(n - 1)

According to Python purists, every function must have a docstring. One reason docstrings are useful is because you canread the docstring for a function in the interpreter by using the help() built-in function, e.g.,

>>> help(fact)Help on function fact in module __main__:

fact(n)return n!

>>> help(print)Help on built-in function print in module builtins:

print(...)print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

Prints the values to a stream, or to sys.stdout by default. Optional keyword arguments: file: a file-like object (stream); defaults to the current sys.stdout.

... and so on

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 3

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

References1. Python PEP 257: https://www.python.org/dev/peps/pep-0257/

3.2 The Standard Type HierarchyAll data in Python are represented by objects. Each object has an identity, a type, and a value. The identity of an objectnever changes once the object is created; you may think of it as the object's address in memory. The object's type deter -mines the operations that may be performed on the object. The type(object) function returns the type of object as a string.The value of some objects can change; such objects are called mutable. If the value cannot change, the object is immut-able. An object's mutability is determined by its type: int, float, string, set, and tuple objects are immutable. On theother hand, list and dictionary objects are mutable.

Objects are automatically garbage-collected when no longer in use.

Some objects contain references to other objects; these types of objects are called containers. For example, the set, list,string, and tuple types are all container types. An immutable container, e.g., tuple, may contain references to mutableobjects. In this case, the values of the mutable objects within the container may be changed, but the container itself maynot be changed, i.e., we cannot change a reference to a object, e.g.,

>>> t = ([1, 2, 3],[4, 5, 6],[7, 8, 9]) t is a 3-tuple; each element of t is a list.>>> t[0] To print the value of variable var in the interpreter, type var.[1, 2, 3]>>> t[1][4, 5, 6]

>>> t[0][1] = 7 t[0] is [1, 2, 3]; t[0][1] is 2; this statement changes t[0] to [1, 7, 3].>>> t[0] Note: the above is legal because lists are mutable, i.e., we change the value[1, 7, 3] of list elements.>>>t[0] = [100, 200, 300] Try to change the tuple t by making t[0] refer to a different list; blows upTraceback (most recent call last): with TypeError exception because t is immutable.

...TypeError: 'tuple' object does not support item assignment

The other three possibilities are: a mutable container that contains a mutable object (both the object's value and the con -tainer's reference to the object can be changed); a mutable container that contains an immutable object (the object'svalue may not be changed but the container's reference to the object can be changed); and an immutable container thatcontains an immutable object (neither the object's value or the container's reference to the object may be changed).

References1. Python Lang. Ref - §3 Data Model: https://docs.python.org/3/reference/datamodel.html2. Python Std. Lib - §4 Built-In Types: https://docs.python.org/3/library/stdtypes.html

3.2.1 NoneThere exists just one object of this type, named None, which signifies the absence of a value in some situations, e.g., it issimilar to null in C++ and Java. Note that when treated as a Boolean value, None is equivalent to False.

3.2.2 Numbersint Signed integers of unlimited range, subject to the amount of virtual memory available to the interpreter.bool Two objects of type bool: True and False. When treated as an int, True is 1 and False is 0.float Real numbers, stored internally in double-precision floating point format, i.e., a double uses 8-bytes of memory.complex Complex numbers, e.g, z = 2.3 - 3.1j. z.real is 2.3 (a float) and z.imag is -3.1 (also a float).

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 4

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

3.2.3 SequencesA sequence is a finite ordered set of objects indexed by nonnegative integers (starting at 0). The built-in function len()returns the number of elements in the sequence. For example,

>>> L = [1, 2, 3] L is a list containing 3 objects, all ints.>>> len(L)3

>>> s = "Fred" s is a string containing four characters.>>> len(s)4

Sequences support slicing operations. A slice of a sequence S is a subsequence of elements from S. The slice notation s[i:j]selects all items with index x such that i ≤ x < j, i.e., the element at j is not part of the slice. Slice notation also permits athird parameter, e.g., s[i:j:k] refers to those elements at index x such that x = i + nk, n 0 and ≥ i ≤ x < j. Examples,

>>> name = "Fred Flintstone" Variable name is of type <class 'str'>.>>> name[0]'F'>>> name[0:5]"Fred "

>>> name[2] = "X" Illegal assignment statement because strings are immutable.>>> name[1:14:3] Indices are 1, 4, 7, 10, and 13."r isn"

See §3.8 for more information on using slices.

3.2.3.1 Immutable SequencesImmutable sequences are sequences containing objects whose value cannot be changed after being created.

str Represents strings. In v3, all strings are encoded in Unicode (this is a major difference from v2).tuple A sequence of one or more objects, may be homogeneous (all of the same type) or heterogeneous (different types).bytes An array of 8-bit bytes.

Immutable sequences, such as str and tuple, are hashable. Let me try to explain what that means. The dict data struc-ture type, §3.2.5, is also called a map or an associative array, and is used to map keys to values,

>>> d = { 'fname': 'bart', 'lname': 'simpson'} d is a dict; key 'fname' maps to value 'bart' and key 'lname'>>> d['fname'] maps to value 'simpson'.bart>>> d['lname']simpson

A hash function is used in the dict data structure to generate unique numeric keys from the symbolic keys. For example,the symbolic key 'fname' might map to numeric key 2992 and the symbolic key 'lname' might map to numeric key 1002.Since immutable sequences are hashable, we can use an immutable type such as tuple as a dict key, e.g.,

>>> t1 = (1, 2, 3) t1 is a 3-tuple>>> t2 = (4, 5, 6) t2 is a different 3-tuple>>> d = {t1: "foo", t2: "bar"} d is a dict with two keys: tuples t1 and t2.>>> d[t1] Print the value to which tuple t1 maps to.'foo'

>>> d[t2] Print the value to which tuple t2 maps to.'bar'

>>> d[(1, 2, 3)] Print the value to which tuple (1, 2, 3) maps to.'foo'

>>> d[(4, 5, 6)] Print the value to which tuple (4, 5, 6) maps to.'bar'

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 5

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

>>> d[(1, 3, 2)]

Traceback (most recent call first): Tuples are ordered so (1, 2, 3) and (1, 3, 2) are not the same tuple..... (1, 3, 2) is not a key in d so this operation will raise a KeyError exception.

KeyError: (1, 3, 2)

Mutable sequences, since they can change value, are not hashable because the dict implementation requires constant keys.

3.2.3.2 Mutable SequencesMutable sequences are sequences containing objects whose value can be changed after being created.

list A list of objects. May be homogeneous or heterogeneous, e.g, L = [1, 2, 3] or M = [1, "Fred", 2+3j].bytearray Like bytes but each object is mutable.

As mentioned in §3.2.3.1, mutable sequences are not hashable and one effect of this is that mutable sequences cannot beused as keys in a dict.

3.2.4 SetsA set is an unordered finite collection of unique, immutable objects, i.e., mutable objects such as lists, cannot be stored ina set. Sets are also nonindexable, e.g., if s is a set then s[0] = somevalue is an invalid assignment statement because wecannot index the elements of s. Generally, elements are retrieved from a set by iterating over the elements of the set, e.g.,

>>> planets = {"mercury", "venus", "earth", "mars", "jupiter", "saturn", "neptune", "uranus"}

>>> planets[2] Illegal because set objects are non-indexable.>>> for p in planets: Set elements can be retrieved by iterating over the element of the set.

print(p) Prints "mercury", then "venus", then "earth", and so on.

Sets are also not hashable. Note that set elements may be homogeneous or heterogeneous, e.g., s = {1, 2, 3} or t = {1,"Fred", 2 + 3j}.

3.2.5 Mapping or DictionaryA mapping or dictionary is a finite set of objects indexed by index sets.

dict A mapping of keys and values, e.g., d = {'fname' : 'kevin', 'lname' : 'burger'}. Here, 'fname' (a key) ismapped to 'kevin' (a value) and 'lname' is mapped to 'burger'. d['fname'] evaluates to 'kevin' and d['lname']to 'burger'.

If m is a mapping, then m[index] selects the element of m at index index. As discussed in §3.2.3.1 and §3.2.3.2, a key mustbe an immutable object, i.e., one that cannot change value. This precludes a list object from being the key.

3.2.6 Callable TypesA callable type is one to which the function call operator () can be applied.

function A user-defined function object is like a function in all other languages.instance method An instance method is a function within a class definition that belongs to the object.built-in function Functions that are built-in to the language, e.g., len(). See [1] for a list of built-in functions.class A class is callable, generally so as to act like a factory to create new objects of the class.

The definition of a function creates a function object that can be used in the same way that other objects can. Forexample, a function may be passed as an argument to a function,

>>> def fact(n): Defines the factorial function, returns n!""" Return n! """ This is a docstring. Typing help(fact) will display the docstring.if n < 2: 0! = 1! = 1

return 1

else: n! = n * (n - 1)!return n * fact(n - 1)

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 6

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

>>> def cube(n, funct):""" Returns the cube of the return value from funct(n). """x = funct(n)return x * x * x

>>> g = cube g is a function object that refers to cube().>>> g(3, fact) Calls cube(3, fact) which returns (3!)3

216

References1. Python Std. Lib. - §2 Built-In Functions: https://docs.python.org/3/library/functions.html

3.2.7 Scripts and ModulesSee [1, 2]. A script is a Python source code file that can be executed by the Python interpreter. The convention is thatscripts have a .py extension, e.g.,

# ascript.pya = 1b = 2print(a + b)

This script can be interpreted by running python3 ascript.py from the command line or however your IDE does it. Amodule is a file containing Python definitions of functions and statements, e.g.,

# fact.pydef fact(n):

if n < 2: # 0! = 1! = 1return 1

else: # n! = n × (n-1)! return n * fact(n - 1)

Scripts and modules appear to be the same thing, and in a way, they are, but the primary difference is that a module con-tains class and function definitions that can be imported and used in other modules with the import statement whilescripts are like programs that are to be run.

>>> import fact The syntax is: import module>>> print(fact.fact(4)) We have to write module.function() to access the function.24

The import statement imports every class and function definition from the module. To import just one definition,

>>> from fact import fact The syntax is: from module import definition>>> print(fact(4)) We can now omit the module. part when calling fact.fact().24

Multiple definitions can be imported by writing from module import def1, def2, .... Python does not require a script or module to have a main() function. The first statement that is executed is the one that appears first in the file, e.g.,

# args.pyimport sys # This statement is executed first

def print_args(args_list): # Next, this function definition is compiledfor a in args_list:

print(a)

print_args(sys.argv) # Next, this statement is executed

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 7

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

$ python3 args.py one two threeargs.py This value is sys.argv[0].one sys.argv[1].two sys.argv[2].three sys.argv[3].

The first executable statement of args.py is the import statement. After the import statement is executed, the functiondefinition of print_args() is seen and compiled into bytecode format, then the function call to print_args() takes place.Scripts and modules have a __name__ attribute. When a module is imported, the __name__ attribute evaluates tothe name of the module sans the filename extension. For example, if we import args.py then __name__ evaluates to"args". On the other hand, when args.py is executed as a script from the command line, __name__ evaluates to"__main__" Therefore, it is common to create a Python source code file that can function as both a script and amodule,

# args.pyimport sys # This line is executed first

def main(): # I like to provide a main() function, listed first in the file print_args(sys.argv) # When the definition is seen by the interpreter, main() will be compiled

def print_args(args_list): # Next, the interpreter sees the definition of print_args(), which is for a in args_list: # now compiled print(a)

if __name__ == "__main__": # Were we invoked as a script? If so, execute main(). main()

Now, when args.py is run from the command line, __name__ will evaluate to "__main__" and the if statement condi-tion will be true, so main() will be called to execute the program. On the other hand, if args.py is imported as a module,__name__ will evaluate to "args" so the if statement condition will be false; main() will not be called, but the func tiondefinitions of the module will be available for use in other scripts and modules.

References1. Python Tutorial - §6 Modules: https://docs.python.org/3/tutorial/modules.html2. Python Lang. Ref. - §5 The import system: https://docs.python.org/3/reference/import.html

3.2.8 Text File I/O, File Objects, Reading from Stdin and Writing to StdoutThe Python io module provides the main facilities for dealing with various types of I/O: text I/O, binary I/O, and rawI/O. We will only discuss text I/O, which deals with string objects. Calling the built-in function open() and passing astring argument as the file name will open a text file for reading or writing. open() returns a file object which is used asa handle to file I/O methods.

>>> fin = open("fileio.py", "r") Open fileio.py for reading, use fin (file input) as the file handle..>>> fout = open("fileio.out", "w") Open fileio.py for writing, use fout (file output) as the handle....

>>> fin.close() Streams should be closed when done reading or writing.>>> fout.close()

The base class used for text I/O streams is io.TextIOBase. The more useful methods of TextIOBase are listed in §16.2.3.4of [3]. Specifically, familiarize yourself with these methods,

read(size) Read and return at most size characters from the file, returning a string.readline() Read until end of line or end of file and return the read text as a string. Note the end of line char is included.

Python converts the Windows text file end of line character sequence Carriage Return/Line Feed (ASCII13/10) into a single Linefeed character, denoted '\n' (ASCII 10). readline() returns the empty string if theend of file has been reached.

write(s) Write string s to an output text file. Returns the number of successfully written characters.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 8

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

A simple for loop can be used to read each line of a text file, one at a time, e.g.,

>>> for line in fin: Iterates over each line of the input file, line is a string object.print(line) In this example, we just print each line.

Three special file objects sys.stdin, sys.stdout, and sys.stderr are automatically opened. Reading from sys.stdin in will readtext from the keyboard or, if stdin has been redirected, will read text from a file or some other Linux program. Writing tosys.stdout will write text to the terminal or, if stdout has been redirected, to a text file or as input to another Linux pro-gram. In Unix systems, stderr is the stream to which error messages should be directed, although error messages are frequ-ently directed to stdout.

The standard built-in function for reading input is the input() function which reads strings from sys.stdin. The input()function has one argument, an optional string which is a prompt to be displayed on the terminal before reading input.input() returns a str with the end of line character removed. Note: in Python 2, input is a statement not a function.

The standard built-in function for writing output is the print() function which writes text to sys.stdout. print() can have avariable number of arguments specifying the text to be displayed. Following the list of objects to be printed are twooptional keyword arguments: sep which is ' ' (space) by default and end which is '\n' by default. sep is a string whichspecifies the string to be printed as a separator between each pair of objects. Since it is the space character by default, asingle space is printed between each pair of objects. To specify that nothing is to be printed, pass sep = '' (two singlequote marks; alternatively, use "") as the argument to print(). The second default keyword is end which specifies thestring to be printed after the line of text is printed. The default is to print a newline character. If you want to print twolines of text on the same line using two print() statements, then specify end = '' (or "") for the argument. Examples,

# print.pyx = input()age = input("How old are you? ")print("You are", age, " years old.")print("You are", age, "years old.", sep=' ')print("You are", age, "years old.", sep='**', end='')print("Goodbye")x = x + ageprint(x)x = int(x) + int(age)print(x)x = int(x + age) # an exception will occur because x is an int and age is a string

$ python3 print.py34 No prompt was displayed, entered 34, so "34" is assigned to x.How old are you? 31 Prompt is displayed. "31" is assigned to age.You are 31 years old. sep is ' ' by default.You are 31 years old. Specifying sep = ' ' is the same as not specifying sep.You are**31**years old.Goodbye ** is printed between each pair of objects.3431 String concatenation since x and age are both strings3462 Convert "3431" to int, convert "31" to int, assign 3462 to x.Traceback (most recent call last): ...TypeError: unsupported operand type(s) for +: 'int' and 'str'

One last example. This code snippet simply sends the input read from sys.stdin to sys.stdout.

for line in sys.stdin:

line = line.strip() Removes leading and trailing whitespace from line.print(line) Print line. Since \'n' was removed, all lines will print on the same console window line.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 9

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

References1. Python Std. Lib. - §2 Built-In Functions - open(): https://docs.python.org/3/library/functions.html#open2. Python Tutorial - §7 Input and Output: https://docs.python.org/3/tutorial/inputoutput.html3. Python Std. Lib. - §16.2 io Module: https://docs.python.org/3/library/io.html#io-overview4. Python Std. Lib. - §2 Built-In Functions - input(): https://docs.python.org/3/library/functions.html#input5. Python Std. Lib. - §2 Built-In Functions - print(): https://docs.python.org/3/library/functions.html#print

3.3 Expressions and operatorsSee [1]. An expression is a combination of things (a highly technical term) which evaluates to a value at run-time, forexample, 2 * 3 - 5 evaluates to 11.

Arithmetic ConversionsImplicit arithmetic conversions occur when the operands of an operator are of two different types. If either operand is oftype complex, the other is converted to complex. If either operand is of type float, the other is converted to float. Other -wise, both operands must be integers.

AtomsSee [2]. An atom is the most basic element of an expression and is either an identifier, a literal, or an enclosure.Identifiers are names for things, e.g., the name of a variable or function. A literal is an immutable value of a specific datatype, e.g., 123 (int literal), 3.14 (float literal), 2+3j (complex literal), "abc" (string literal), [1, 2, 3] (list literal), (1, 2,"Fred") (tuple literal), {1, 2, 3} (set literal), {'x': 1, 'y': 2} (dictionary literal). Enclosures consist of,

Parenthesized forms: ( expression_list ) (1, 2, 3) is a tupleList displays: [ expression_list ] [1, 2, "Fred"] is a listSet displays: { expression_list } { 'a', '1', 2+3j } is a setDict displays: { key_datam_list } { 'x': 1, 'y': 2, 'z': (3, 4), 'a': [1, 2, 3] } is a dictionary

Operators A list of the Python operators is shown below in order of decreasing precedence; note that a couple of the lesser-usedoperators are omitted. Like most programming languages, any expressions inside parentheses are evaluated before expres-sions outside parentheses. Those expressions at the innermost level of parentheses are evaluated before those at the outer -most level. Operators at the same precedence level are evaluated left to right. Unlike C/C++/Java, Python has anexponentiation operator. Python, rather stupidly in my opinion, does not implement the increment/decrement operators.

Operator Precedence Table, see [3].0. (expr), [expr], {expr}, {key:val} Construct tuple (), construct list [], construct set {}, construct dict {}.1. [idx], [idx1:idx2], expr(), . Sequence subscript, sequence slicing, function call, access attribute, e.g., x.name2. ** Power (exponentiation); right-associative: 2**3**4 is 2**(3**4), not (2**3)**4.3. -, +, ~ Unary negation, unary plus, one's complement or binary NOT.4. *, /, //, % Mult, real division, floor division (integer division), modulus (works on reals).5. +, - Addition, subtraction.6. <<, >> Shift left, shift right.7. & Bitwise AND.8. ^ Bitwise XOR.9. | Bitwise OR.10. <, >, <=, >=, ==, != Relational comparisons. Note: a < b <= c is equiv to a < b and b <= c

in, not in, is, is not Membership test.11. not expr Boolean/logical NOT.12. and Boolean/logical AND.13. or Boolean/logical OR.14. if cond else expr If-else conditional; equivalent to the C ternary operator ?:

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 10

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

An expression list containing at least one comma yields a tuple, e.g., in print(1, 2, 3), (1, 2, 3) is a tuple of len 3.Similarly, return a, b, c causes the 3-tuple (a, b, c) to be created and returned. Weird syntax alert: to create a tuplecontaining one value, one might expect that tuple-var = (value) would suffice, but since () can be used in expressions toalter the default precedence, this statement will be interpreted as "assign value to variable tuple-var." Rather, writetuple-var = (value), where the trailing comma tells the interpreter to treat value as a 1-tuple, e.g., a = 5, creates the 1-tuple (5).

Assignment = and combined assignment (+=, -=, *=, etc) are not operators as they are in C++ and Java, rather theyare statements (more later). The symbol * can be used for repetition, e.g.,

"abc"*3 evaluates to "abcabcabc"[1, 2, 3]*2 evaluates to [1, 2, 3, 1, 2, 3].Note that 2 * 4 is 16 and not 2222; in this context * is interpreted as multiplication; use "2"*4 to generate "2222.int("1" + "0"*100) is the integer 1 followed by 100 zeros, i.e., 10100.

References1. Python Lang. Ref. - §6 Expressions: https://docs.python.org/3/reference/expressions.html2. Python Lang. Ref. - §6 Atoms: https://docs.python.org/3/reference/expressions.html#atoms3. Python Lang. Ref. - §6 Operator Prec.: https://docs.python.org/3/reference/expressions.html#operator-precedence

3.4 Simple StatementsA simple statement is comprised of a single line of code; the different types of statements are discussed in [1] and in theremainder of this section. By convention, Python programmers place one statement per line, but that is a convention I donot always agree with so in some situations I like to write multiple statements on the same line; this can be done by sepa -rating each pair of statements with a semicolon. In the remainder of this section, we will discuss the more useful state-ments. More information can be found at [1].

References1. Python Lang. Ref. - §7 Simple Statements: https://docs.python.org/3/reference/simple_stmts.html

3.4.1 Expression StatementEvaluates to a value, e.g., writing a ** b - 2 % c as a statement will cause the expression to be evaluated.

3.4.2 Assignment StatementThe assignment statement using = is used to bind or rebind a name to a value. Examples,

>>> a = 3 Variable a is bound to the int 3.>>> b = 2 ** a - 5 The expression is evaluated to 3 and b is bound to 3.>>> a, b = 1, 2 Variable a is bound to 1 and b is bound to the 2.>>> a, b, c = foo(x, y, z) Function foo() is called, returning a 3-tuple; a, b, c are bound to the tuple elements.

3.4.3 Augmented Assignment StatementThese statements function like the equivalent operators in C, C++ and Java,

+= augmented assignment-= subtraction*= multiplication/= floating point division

//= floored division%= modulus<<= shift left>>= shift right

&= augmented bitwise AND^= augmented bitwise exclusive-OR|= augmented bitwise OR

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 11

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

3.4.4 Pass StatementThe pass statement does nothing and is used in places where a statement is required but no code needs to be executed.Example,

def sqr(n): # will implement later pass # pass for now

3.4.5 Del StatementThe del identifier statement deletes the identifier named identifier from either the local or global namespace, e.g.,

# del.pyage = input("How old are you? ")print("Your age is", age)L = [age, age, age]print(L)del ageprint(age)del Lprint(L)

$ python3 del.pyHow old are you? 22Your age is 22['22', '22', '22']Traceback (most recent call last): ...NameError: name 'age' is not definedTraceback (most recent call last): ...NameError: name 'L' is not defined

3.4.6 Return StatementThe return statement is used to return an expression list from a function, e.g.,

def sqr(n):return n * n

def foo(x, y):x += 1y -= 1return x, y, z # The interpreter packs x, y, z into the 3-tuple (x, y, z) and returns the tuple

3.4.7 Break and Continue StatementsThe break and continue statements operate just as they do in C, C++, and Java.

3.4.8 Import StatementAlso see §3.2.8. There are several different forms of the import statement which is used to access definitions in othermodules. The two forms we will use are,

import module # imports all definitions from module module into this modulefrom module import def1 [, def2, ...] # imports only the definitions of def1, def2, ... from module

Note that import module is the same as from module import *. In the first form, all definitions in module are im-ported but in the second, only the listed definitions are imported. Example,

>>> import math Imports all definitions from the math module.>>> print(math.log10(1000)) Must refer to definitions by writing modname.defname>>> from sys import argv Imports only the definition of argv from the sys module.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 12

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

>>> if argv[1] == "-t": foo() Must refer to definition of sys.argv as simply argv

When a module is imported, its __name__ attribute will be set to the name of the module; remember, with scripts, the__name__ attribute will be set to the script filename.

3.5 Compound StatementsA compound statement is a statement which contains groups of other statements (compound statements are frequentlycalled blocks by C, C++, and Java programmers). In general, a compound statement spans multiple lines of code. Acompound statement consists of one or more clauses, where a clause consists of a header and a suite. A clause header isan identifying keyword and ends with a colon. A suite is a group of statements controlled by a clause. For example, an ifstatement is one type of compound statement,

if a < b: # the header of this compound stmt is if a < b which is followed by a required colonc = d - e # these two assignment stmts form a suitex += 1 # note that the suite is indented one tab level beneath the header

if a > 0: b -= 1 # a short compound stmt can be written on one line although this bothers some people

Be aware that Python does not use delimiting symbols, such as braces { ... }, to specify the beginning and end of a suite.The suite ends with the first line of text that is not at the same indentation level as the suite. In the remainder of thissection, we will discuss the more useful compound statements. More information can be found at [1].

References1. Python Lang. Ref. - §8 Compound Statements: https://docs.python.org/3/reference/compound_stmts.html

3.5.1 If StatementThe Python if statement is very similar in form and function to if statements in C, C++, and Java. Examples,

if a > b: # this line is the clause header c = 1 # this line is the suite; notice the suite is indentedx = 0 # this line is the next statement following the if statement; it is not part of the suite

if a > b: # first clause headerc = 1 # first suite

else: # second clause headerd = 2 # second suite

if gpa > 3.8:print("Summa cum laude")

elif gpa > 3.6: # elif is use rather than else ifprint("Magna cum laude")

elif gpa > 3.4:print("Cum laude")

else:print("Well, at least you graduated)

3.5.2 While StatementThe Python while statement is very similar to its C, C++, and Java counterpart.

while a > b: # clause headerc -= 1 ; d = 2 + c # these three statements are the suitex = foo(c, d)

while x - 1 != 4:z -= 1r += 1

else: # if the conditional expression is false when first evaluated, then the statementsz = r = 0 # in the else: suite are executed. Otherwise, they are not executed.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 13

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

3.5.3 For StatementThe for statement is used to iterate over the elements of a sequence or some other iterable object. To iterate meansto access each element of the sequence, one after the other, in order. The syntax is,

for target_list in expression_list:suite

[ else:suite ]

The expression_list is evaluated once and must evaluate to an object that can be iterated over. The suite is then executedonce for each object in expression_list. The else clause is optional; if present, it is executed once after the final iteration.A common for loop that iterates over the integers in a range is created using the built-in range() function to generate theexpression_list. The syntax of range() is,

range(stop) or range(start, stop, [step])

The arguments to range() must be integers. start defaults to 0 if omitted and step defaults to 1. It is important to notethat [start, stop) is the interval that range() generates, i.e., [start, stop - 1] is the generated range. Examples,

range(10) when iterated over yields: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. Note range(10) is equivalent to range(1, 10, 1).range(2, 9) when iterated over yields: 2, 3, 4, 5, 6, 7, 8. Equivalent to range(2, 9, 1).range(2, 101, 2) when iterated over yields: 2, 4, 6, 8, ..., 96, 98, 100.range(10, 0, -1) when iterated over yields: 10, 9, 8, 7, 6, 5, 4, 3, 2, 1.range(10, -3, -3) when iterated over yields: 10, 7, 4, 1, -2.

for i in range(10): # prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9print(i)

for n in range(0, 101, 2): # prints 2, 4, 6, 8, ..., 96, 98, 100print(n)

for n in range(10, -3, -3): # prints 10, 7, 4, 1, -2print(n)

List = [2, 3, 5, 7, 11, 13, 17, 19] # define L as a listfor item in List: # prints 2, 3, 5, 6, 11, 13, 17, 19

print(item)

s = "Fred Flintstone" # define s as a strfor char in s: # prints 'F', 'r', 'e', 'd', ..., 'n', 'e'

print(char)

3.5.4 Function DefinitionsA function definition is a compound statement. Functions operate the same as in C, C++, and Java. The function mustbe defined before it can be called or executed. When calling the function, we may pass arguments to the function, insqrt(n), we refer to n as the function argument or simply argument. When defining a function that has arguments, we referto the variable names in the function definition header as parameters (some people and books use the terms actualparameters and formal parameters in place of arguments and parameter). A function returns an expression list, see§3.3, which means that a function can return as many values as it needs to. Parameters and variables that are created inthe function have local scope, meaning that the parameter or local variable becomes undefined when the function re-turns. Examples,

def sqr(n): # A function is a type. Q? What does print(type(sqr)) display?return n * n # n is a parameter with local scope; we return 1 value

def cube(n):return sqr(n) * n

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 14

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

def fact(n):if n < 2:

return 1else:

return n * fact(n - 1)

See §3.2.7. Note that Python does not require a main() function as in C, C++, and Java. For example, here is the stand-ard Hello World program in Python.

# hello.pyprint("Hello world.")

To create a module containing one or more functions and to designate one of those function as the main function,

# module-foo.pydef main(): # main() could be called anything, such as start() or begin()

n = input("Enter an integer > 0? ")m = input("Enter an integer > 0? ")print(foo(n, m))

def foo(x, y):return x ** y / y ** x

if __name__ == "__main__": # if this module was executed as script, then call main()main()

__name__ is a module attribute (accessible as just __name__ within the module) that equates to the name of amodule when the module is imported into another module. When a module is executed as a script, __name__ equates tothe name of the script file sans the filename extension. Example,

# foo.pyprint("__name__ in foo.py is", __name__)

def main:print("Executing main() in foo.py")

if __name__ == "__main__":main()

# bar.pyprint("__name__ in bar.py is", __name__)

def main():print("Executing main() in bar.py")

if __name__ == "__main__":main()

# baz.pyimport foo ; import barprint("__name__ in baz.py is", __name__)

def main():print("Executing main() in baz.py")

if __name__ == "__main__":main()

$ python foo.py Run foo.py as a script. __name__ will be "__main__".__name__ in foo.py is __main__Executing main() in foo.py

$ python bar.py Run bar.py as a script. __name__ will be "__main__".__name__ in bar.py is __main__Executing main() in bar.py

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 15

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

$ python baz.py Run baz.py as a script. foo.py and bar.py are imported modules;__name__ in foo.py is foo their __name__ attributes will be "foo" and "bar". Since baz.py is __name__ in bar.py is bar run as a script, __name__ baz.py will be "__main__".__name__ in baz.py is __main__Executing main() in baz.py

A convenient use for __name__ is to implement code that is only executed when the module is executed as a script;common practice in Python is to implement code that will test the module. Example,

# baz.pyimport fooimport bar

def main():...

def test():run_test_case1()run_test_case2()run_test_case3()...

if __name__ == "__main__": # When baz.py is executed as a script, __name__ will be "__main__" sotest() # test() will be called to test the script. On the other hand, if the

else: # module baz is imported into another module, __name__ will be "baz" somain() # main() will be called to initialize the module, if necessary.

3.6 Built-in FunctionsPython has a number of built-in functions, see [1]. You should familiarize yourself with some of the more useful ones,including the following (try these out in the interpreter): abs(), bin(), chr(), float(), hex(), input(), int(), len(), list(), max(),min(), ord(), print(), range(), reversed(), round(), set(), sorted(), str(), sum(), tuple(), and type().

References1. Python Std. Lib. - §2 Built-In Functions: https://docs.python.org/3/library/functions.html

3.7 Mathematical FunctionsSee [1]. The math module contains common mathematical functions that operate on integers and floats. Import the cmathmodule for complex numbers functions. Example,

>>> import math Imports all definitions from the math module. Write math.funct() to call funct().>>> from math import log Import just the definition of log() from the math module. Write funct() to call funct().>>> print(math.sqrt(13)) Call sqrt() function. Note that we specify the module name.3.605551275463989

>>> print(log(10) Call log() function. Note that the module name must be omitted.

References1. Python Std. Lib. - §9.2 math Module and Mathematical Functions: https://docs.python.org/3/library/math.html

3.8 Strings and the str Data TypeA Python string is a sequence of zero or more Unicode codepoints (characters). Python uses the built-in str data type torepresent strings. A string literal is a string which is enclosed in either double quotation marks, e.g., "Fred", or singlequotation marks, e.g., 'Fred'. If "" are used as the string delimiting characters then embedded ' marks are treated asordinary characters, e.g., "Fred said, 'Hello'" is the string literal Fred said, 'Hello'. The converse is also true. It is alsopermissible to use \" or \' within a string literal to represent the literal " and ' characters, e.g., "Fred said, \"Hello\"" isthe string Fred said, "Hello".

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 16

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

See [2] for a list of string escape sequences. Since Python is based on C, many of the C, C++, and Java escapesequences are the same in Python. More specifically, the reader should be comfortable using \n (newline or linefeed escapesequence), \\ (becomes literal \ char), \" (becomes literal " char), and \' (becomes literal ' char).

Python also supports raw strings which are string literals preceded by either r or R and within the string literals, noescape sequences are recognized, e.g., in "C:\foo\bar", \f and \b will be interpreted as escape sequences. \f is the formfeed escape sequence (in the old days of teleprinters sending \f to the teleprinter would cause the paper to scroll up up tothe top of the next page) and \b represents the backspace character. However, if the programmer means to write a stringliteral that represents a DOS pathname (go to drive C, go the foo subdirectory, and then go to the bar subdirectory) thenhe or she has to either use \\ in place of the \ characters, e.g., "C:\\foo\\bar", or he or she can define the string literal asa raw string, e.g., r"C:\foo\bar" is the string C:\foo\bar.

If, for some reason, a string literal needs to space several line of code, then a multi-line string literal can be written insidea pair of """ characters.

String concatenation is performed using the + operator, e.g., "Fred" + " " + "Flintstone" results in "Fred Flintstone".

String repetition uses the * symbol to create a string literal contains two or more occurrences of the base string, e.g.,"abc"*3 evaluates to "abcabcabc"; I am referring to "abc" as the base string. One use of this might be to create a largeinteger value, e.g., "1" + "0"*100 becomes the string literal "1000...000" where there are one hundred 0 characters in thestring. This string can be turned into an int by calling int("1" + "0"*100); the return value is the integer 10100.

String objects are immutable, indexable, sequences. Indexable means we can access individual characters using indices (orsubscripts), e.g.,

"abcdef"[0] is "a" Note: strings indices are numbered starting at 0."abcdef"[-1] is "f" A negative subscript means to start from the end of the string (EOL is at index 0)."abcdef"[-3] is "d" If the EOL character is at index 0, then "abcdef"[-3] is the third char moving bw from the end.

String subsequences can be accessed using slice notation [i:j] and [i:j:k], see §3.2.3. Examples,

'abcdef'[2:4] is 'cd' Note that the characters at indices 2 and 3 are accessed, the char at index 4 is not included.'abcdef'[:4] is 'abcd' When i is omitted and k > 0, i defaults to the index of the first element; indices are 0 .. 3.'abcdef'[3:] is 'def' j is the index of the last element of the sequence plus 1 when omitted.'abcdef'[2:99] is 'cdef' It is not an error to specify an index that is greater than the index of the last element.'abcdef'[:] is 'abcdef' i is 0 by default, and j is the index of the last element+1, consequently [:] is the entire string.

A third slice argument may be present [i:j:k]. In this case, the selected subsequence consists of those elements at indices i+ 0·k, i + 1·k, i + 2·k, ..., and we stop when i+n·k ≥ j becomes true (remember, the element at index j is not included inthe slice). When omitted, k defaults to 1; examples,

'abcdefghij'[1:10:2] is 'bdfhj' Indices are 1, 3, 5, 7, and 9.'abcdefghij'[:6:2] is 'ace' k > 0 and i is omitted, so i defaults to the index of the first element; indices are 0, 2, 4.'abcdefghij'[::3] is 'adgj' Indices are 0, 3, 6, 9.

Note that when k > 0 and i ≥ j, the selected subsequence is empty, i.e., "" is the result. When k < 0 the accessed elementindices are also at i + 0·k, i + 1·k, i + 2·k, ..., but we stop when i + n·k ≤ j becomes true. When k < 0 and j > i, theselected subsequence is empty; examples,

'abcdefghij'[9:1:-1] is 'jihgfedc' Indices are 9, 8, 7, .., 2.'abcdefghij'[:0:-1] is 'jihgfedcb' When k < 0, by default i is the index of the last element; indices are 9, , 8, ... 1.'abcdefghij'[::3] is 'adgj' Indices are 0, 3, 6, 9.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 17

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

An interesting "side effect" to the way slices operate is that it is possible to reverse the characters of a string using a slice,

>>> s = "abcdef"[::-1] Assigns the reverse of "abcdef" to s.>>> sfedcba

>>> s = s[::-1] Changes s to be the reverse of itself.>>> sabcdef

Being able to reverse a string in one line leads to a very short is_palindrome() function,

def is_palindrome(s):""" Return true if s is a palindromic string. """return s == s[::-1]

Nifty. We mentioned that strings are immutable, which essentially means that we cannot change the contents of the stringafter it has been created. Practically, it means s = "abcdef"; s[2] = "x" is an illegal assignment to s[2] because we areattempting to change the string.

The built-in len() function accepts any argument which is a sequence, including strings: len("abcdef") returns 6. ThePython Standard Library has several useful string methods, see [3]. You might familiarize yourself with the following:capitalize(), find(), lower(), replace(), rfind(), split(), strip(), upper().

Finally, to convert a number into a string, call the built-in str() function, e.g., str(123) is "123", str(3.14) is "3.14", andstr(2.1 - 3.5j) is "3.1 - 3.5j". Conversely, to convert a string representing an integer into an int, use int(), e.g., int("123") is123; to convert a string representing a floating point number into a float, use float(), e.g., float("3.14") is 3.14; and toconvert a string representing a complex number into a complex, use complex(), e.g., complex("2.1 - 5.2j") is 2.1 - 5j.

References1. Python Std. Lib. - §7.1 Common String Operations: https://docs.python.org/3.1/library/string.html2. Python Lang. Ref. - §2.4.1 String and Byte Literals: https://docs.python.org/3/reference/lexical_analysis.html3. Python Std. Lib - §4.7.1 String Methods: https://docs.python.org/3/library/stdtypes.html#string-methods

3.8.1 C printf()-Style FormattingThe method discussed in this section is not the recommended Python3 way to print formatted output, but it will work forus. See [2] for more information about the newer, recommended method for formatting output.

Python permits formatting of the output from a print() function call using a notation which is very similar to the methodused in C and C++ with the printf() function. First, string objects have a unique built-in operator, % which is the stringformatting operator. Given an expression of the format format-string % values, the string formatting operator willreplace conversion specifications in format-string with values from values. As mentioned, format-string is a string andvalues must be a tuple, enclosed in (), unless a single value is being printed. Useful conversion specifications,

%d int%f float%x hex with lowercase hex digits, e.g., 12bc%X hex with uppercase hex digits, e.g., 12BC%e exponential notation with lowercase e, e.g., 1.32e+23%E exponential notation with uppercase E, e.g., 1.32E+23%c single character%s string%% prints a single %

To print a value in a field of a specific width, use %wc where w is the field width and c is the conversion specification; thevalue will be printed right-justified in the field with spaces as padding characters. To print the value in a left-justified field,

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 18

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

use %-wc, where the - sign indicates left-justification. The number of digits after the decimal point for a floating pointnumber is controlled by %.nf, where n is the number and f is the conversion specification. Examples,

a = 190b = 3.14159265828print("a = %d" % a) # prints a·=·190 (where · is a space char)print("a = %d, b = %f" % (a, b)) # prints a·=·190,·b·=·3.141593 (6 digits after . are the default)print("a = %d, b = %.3f" % (a, b)) # prints a·=·190,·b·=·3.142 (round to 3 digits after .)print("%0x" % a) # prints be (190 base 10 = 0xBE)print("0x%0x" % a) # prints 0xbeprint("0x%0X" % a) # prints 0xBEprint("a = %10d, b = %-10.3f." % (a, b)) # prints a·=········190, b·=·3.142····· (- left justifies)

References1. Python Std. Lib. - §4.7: https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting2. Python Std. Lib. - §6.1.3: https://docs.python.org/3/library/string.html#formatstrings

3.9 More on ListsSee [1-3]. A list is a mutable, indexable, sequence data type used to group values. The elements of the list may be homo-geneous (all of the same type) or heterogeneous (of different types). Since lists are indexable, listvar[i] specifies the value inlistvar at index i. List indices are numbered starting at 0, so listvar[i] is the (i+1)-st element of the list. Lists are mutableso it is permissible to assign a value to listvar[i].

A list literal is written as the list of values inside brackets, e.g., [1, 2, 3] is a list of three homogeneous elements. Tocreate an empty list, write listvar = list() or listvar = [], e.g., L1 = list() and L2 = [].

To add an element to the end of a list, call the append() method on the list variable, e.g., L1.append(2) changes L1 from []to [2]. The same effect can be obtained using the += operator, e.g., L1 += [2] would also change L1 from [] to [2].

To append each of the elements of a list L3 to list L4, call the extend() method on L4, e.g., L4.extend(L3) or L4.extend([5,6, 7]). In the second example, if L4 were [1, 2, 3, 4] before the call to extend(), then upon return L4 will be [1, 2, 3, 4, 5, 6,7].

There is a subtle difference between append() and extend() which is important to understand: append() has a singleargument, which is appended to the list. The type of this argument may be just about anything. Consider,

>>> L1 = [1, 2, 3] L1 is a list of length 3.>>> L2 = [4, 5, 6] L2 is a list of length 3.>>> t = (7, 8, 9) t is a 3-tuple.>>> L1.append('a') L1 is now [1, 2, 3, 'a'] and is of length 4.>>> L1.append(L2) L1 is now [1, 2, 3, 'a', [4, 5, 6]] and is of length 5.>>> L1.append(t) L1 is now [1, 2, 3, 'a', [4, 5, 6], (7, 8, 9)] and is of length 6.

Note that when L2 was appended to L1 that the list L2 = [4, 5, 6] was appended to L1 and not the elements of L2.Similarly, when t was appended to L1 the tuple t = (7, 8, 9) was appended to L1 and not the elements of t. Now, considerextend(),

>>> L1 = [1, 2, 3] L1 is a list of length 3.>>> L2 = [4, 5, 6] L2 is a list of length 3.>>> t = (7, 8, 9) t is a 3-tuple.>>> L1.extend('a') L1 is now [1, 2, 3, 'a'] and is of length 4.>>> L1.extend(L2) L1 is now [1, 2, 3, 'a', 4, 5, 6] and is of length 7.>>> L1.extend(t) L1 is now [1, 2, 3, 'a', 4, 5, 6, 7, 8, 9] and is of length 10.

Note that when L1 was extended with L2 that the elements of L2 were appended to L1. Similarly, when L1 was extendedwith tuple t, the elements of t were appended to L1.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 19

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

Being a sequence type, lists are sliceable, e.g., if L is [1, 2, 3, 4, 5] then L[1:3] consist of the elements of L at indices 1 and2, which results in the sublist [1, 2]. L[:4] evaluates to [1, 2, 3, 4]. L[2:] evaluates to [3, 4, 5]. L[::-1] evaluates to [5, 4, 3, 2,1] and L[3:1:-1] evaluates to [4, 3]. L[1:3] = ['a', 'b', 'c'] would change L from [1, 2, 3, 4, 5] to [1, 'a', 'b', 'c', 4, 5]. L = L[::-1] makes L the reverse of L, i.e., the new value of L would be [5, 4, 3, 2, 1] after the assignment.

Two lists may be concatenated using either extend() or the + concatenation operator, e.g., if M is [6, 7, 8, 9, 10] thenL.extend(M) changes L to be [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and L = L + M also changes L to the same value.

The len() function—applicable to any sequence data type—can be applied to lists. If L is [1, 2, 3, 4, 6] then len(L) is 6.

The elements of a list may be just about any data type, including lists, which leads us to lists of sublists, e.g., L = [[1, 2],[3, 4], [5], 6] is a list of length 4, where the first three elements are all lists themselves. To access the individual elements ofa sublist, we specify two subscripts, e.g., L[0][1] refers to the second element of the sublist at index 0 of L: this value is 2.L[2][0] is the first element of the sublist at index 2 of L: this value is 5.

Two-, three-, and multidimensional arrays are created in Python as lists of sublists, e.g., consider this C array A which is atwo-dimensional array with three rows and three columns. The Python list equivalent is shown to the right,

int A[][] = { A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] Note:{1, 2, 3}, A[0][0] is 1; A[0][1] is 2; A[0][2] is 3{4, 5, 6}, A[1][0] is 4; A[1][1] is 5; A[1, 2] is 6{7, 8, 9} A[2][0] is 7; A[2][1] is 8; A[2][2] is 9

};

A list may be unpacked to separate the list elements, e.g., if L is [1, 2, 3] then a, b, c = L results in a being assigned 1, bis assigned 2, and c is assigned 3. A ValueError exception is raised if the length of L does not match the number of vari-ables on the left-hand side of the assignment statement. However, a, b = L[0:2] legally assigns 1 to a and 2 to b.

Reference [3] documents the list class methods. The more common methods that we are likely to use in our programs arelisted below. You should familiarize yourself with these,

L.append(x) Adds x to the end of L. x should be a single value.L.extend(x) Unpacks x and adds each individual value to L.L.insert(i, x) Inserts x into L before the element at index i. Note that insert() does not unpack x.L.remove(x) Removes the first occurrence of x from L. Raises a ValueError exception if x is not in L.L.pop([i]) With no arg, removes and returns the last element of L. Otherwise, removes and returns the elem at i.L.clear() Makes L empty. Note this is equivalent to del L[:] (what does del L do?)L.index(x) Returns the index in L of the first occurrence of x. Raises a ValueError exception if x is not in L.L.count(x) Returns the number of occurrences of x in L.L.sort() Sorts the elements of L in-place into ascending or order. Set arg reverse to True for descending sort.L.reverse() Reverses the elements of L in-place. Note this is equivalent to L[:] = L[::-1].L.copy() Returns a shallow copy of L. Note this is equivalent to L[:].copy.deepcopy(L) Returns a deep copy of L. To call copy.deepcopy() the copy module must be imported.

References1. Python Tutorial - §3.1.3 Lists: https://docs.python.org/3/tutorial/introduction.html#lists2. Python Tutorial - §5.1 More on Lists: https://docs.python.org/3/tutorial/datastructures.html3. Python Std. Lib. - §4.6 https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range

3.9.1 List Example: Implementing a Stack Data Structure TypeA list may be used as a stack data structure, e.g.,

>>> stack = list() Creates an empty stack.>>> stack.append(1) Push 1.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 20

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

>>> stack[1]

>>> stack.append(2) Push 2.>>> stack[1, 2]

>>> stack.append(3) Push 3.>>> stack[1, 2, 3]

>>> top = stack[len(stack)-1] Returns the element on top of the stack, i.e., a peek operation.>>> top3

>>> stack When performing the peek operation, the top element was not removed.[1, 2, 3]

>>> n = stack.pop() Returns the element on top of the stack, also removing it.>>> n3>>> stack[1, 2]

A stack is a commonly used data structure (remember, it is a LIFO structure) and because having to remember thatstack[len(stack)-1] is the peek operation, it may be helpful to implement a stack data type, which we shall do by creating aclass named Stack. Our Stack data type shall implement the following operations,

clear() Remove all of the elements from the stack, making it empty.is_empty() Return True if the stack is empty.peek() Return the element on the top of the stack, without removing it.pop(n=1) Return the top element on the stack when n = 1; when n > 1, return a list of the top n elementspush(elem) Push element elem onto the stack.push_iterable(i) Iterate over the elements of i, pushing each element onto the stack.size() Return the number of elements on the stack, as an int.str() Return a string representation of the stack.Stack() Create and return a new, empty stack.

See the stack.py source code file on the course website for the Stack class implementation, also shown below,

#***********************************************************************************************************************# FILE: stack.py## DESCRIPTION# Illustrates how to write a class that implements a Stack data structure using a list to store the elements. Uses# object composition, i.e., the list object is a data member of the Stack object. An alternative way to define the# Stack class is to make Stack inherit from List.## AUTHOR# Kevin Burger ([email protected])# Computer Science & Engineering# Arizona State University, Tempe, AZ 85287-8809# Web: www.devlang.com#***********************************************************************************************************************from copy import deepcopy

#=======================================================================================================================# CLASS: Stack (note that Python convention is to capitalize class names)#=======================================================================================================================class Stack(object): def __init__(self): """ Create a new empty stack. """ self.clear()

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 21

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

def clear(self): """ Remove all the elements of the stack, making the stack empty. """ self.__stack = list() self.__size = 0

def is_empty(self): """ Return true if the stack is empty. """ return self.__size == 0

def peek(self): """ Return the top element on the stack, without removing it. """ return self.__stack[self.__size - 1]

def pop(self, n = 1): """ When n is 1, return the top element of the stack. When n is > 1, return the top n elements of the stack as a list. """ popped = self.__stack[self.__size-1:self.__size-1-n:-1] self.__stack = self.__stack[:self.__size-n] self.__size -= n return popped[0] if n == 1 else popped

def push(self, elem): """ Push elem onto the top of the stack. """ self.__stack.append(elem) self.__size += 1 return self

def push_iterable(self, iterable): """ Push all of the elements of iterable into the stack. """ for elem in iterable: self.__stack.append(elem) self.__size += 1 return self

def size(self): """ Returns the number of elements on the stack. """ return self.__size

def __str__(self): """ Return a string representation of the stack. """ return "<Stack: __stack = " + str(self.__stack) + ", __size = " + str(self.__size) + ">"

def test_cmp(actual, expected, end_="\n"): if actual == expected: print("pass", end=end_) else: print("fail", end=end_)

def test(): # Testing constructor function Stack(). print("Testing constructor function Stack()... ", end="") stack1 = Stack() test_cmp(stack1.__str__(), "<Stack: __stack = [], __size = 0>")

# Testing push(int). print("Testing push(int)... ", end="") stack1.push(1).push(2).push(3).push(4) test_cmp(stack1.__str__(), "<Stack: __stack = [1, 2, 3, 4], __size = 4>")

# Testing push(list). print("Testing push(list)... ", end="") stack1.push([1, 2, 3, 4]) test_cmp(stack1.__str__(), "<Stack: __stack = [1, 2, 3, 4, [1, 2, 3, 4]], __size = 5>")

# Testing push(tuple). print("Testing push(tuple)... ", end="") stack1.push((1, 2, 3, 4)) test_cmp(stack1.__str__(), "<Stack: __stack = [1, 2, 3, 4, [1, 2, 3, 4], (1, 2, 3, 4)], __size = 6>")

# Testing push(string). print("Testing push(string)... ", end="") stack1.push("abc") test_cmp(stack1.__str__(), "<Stack: __stack = [1, 2, 3, 4, [1, 2, 3, 4], (1, 2, 3, 4), 'abc'], __size = 7>")

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 22

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

# Testing push_iterable(list). Reset __stack to [1, 2, 3, 4]. stack1 = Stack(); stack1.push_iterable([1, 2, 3, 4]) print("Testing push_iterable(list)... ", end="") stack1.push_iterable(['a', 'b', 'c', 'd']) test_cmp(stack1.__str__(), "<Stack: __stack = [1, 2, 3, 4, 'a', 'b', 'c', 'd'], __size = 8>")

# Testing push_iterable(tuple). Reset __stack to [1, 2, 3, 4]. stack1 = Stack(); stack1.push_iterable([1, 2, 3, 4]) print("Testing push_iterable(tuple)... ", end="") stack1.push_iterable(('a', 'b', 'c', 'd')) test_cmp(stack1.__str__(), "<Stack: __stack = [1, 2, 3, 4, 'a', 'b', 'c', 'd'], __size = 8>")

# Test push_iterable(string). Reset __stack to [1, 2, 3, 4]. # Should print "<Stack: __stack = [1, 2, 3, 4, 'F', 'r', 'e', 'd', "Wilma"]>" stack1 = Stack(); stack1.push_iterable([1, 2, 3, 4]) print("Testing push_iterable(string)... ", end="") stack1.push_iterable("Fred") test_cmp(stack1.__str__(), "<Stack: __stack = [1, 2, 3, 4, 'F', 'r', 'e', 'd'], __size = 8>")

# Testing peek() -> element print("Testing peek() -> element... ", end="") x = stack1.peek() test_cmp("x = {}".format(x), "x = d")

# Testing peek() -> sequence stack1 = Stack(); stack1.push([1, 2, 3, 4]) print("Testing peek() -> sequence... ", end="") x = stack1.peek() test_cmp("x = {}".format(x), "x = [1, 2, 3, 4]")

# Testing pop(n = 1). stack1 = Stack(); stack1.push_iterable([1, 2, 3, 4]) print("Testing pop(n=1)... ", end="") x = stack1.pop() test_cmp("x = {}".format(x), "x = 4", end_=", "); test_cmp(stack1.__str__(), "<Stack: __stack = [1, 2, 3], __size = 3>")

# Testing pop(n = 3). stack1 = Stack(); stack1.push_iterable([1, 2, 3, 4, 5, 6, 7, 8]) print("Testing pop(n=3)... ", end="") x = stack1.pop(3) test_cmp("x = {}".format(x), "x = [8, 7, 6]", end_=", "); test_cmp(stack1.__str__(), "<Stack: __stack = [1, 2, 3, 4, 5], __size = 5>")

# Testing size() on a non-empty stack. print("Testing size() on a non-empty stack... ", end="") length = stack1.size() test_cmp("length = {}".format(length), "length = 5")

# Testing size() on an empty stack. print("Testing size() on an empty stack... ", end="") stack1.clear() length = stack1.size() test_cmp("length = {}".format(length), "length = 0")

# Testing shallow copy by assignment. print("Testing shallow copy by assignment... ", end="") stack1 = Stack(); stack1.push_iterable([1, 2, 3, 4, 5]) stack2 = stack1 stack2.push(6) test_cmp(stack1.__str__(), "<Stack: __stack = [1, 2, 3, 4, 5, 6], __size = 6>", end_=", ") test_cmp(stack2.__str__(), "<Stack: __stack = [1, 2, 3, 4, 5, 6], __size = 6>")

# Testing deep copy by calling copy.deepcopy(). print("Testing deep copy by calling copy.deepcopy()... ", end="") stack1 = Stack(); stack1.push_iterable([1, 2, 3, 4, 5]) stack2 = deepcopy(stack1) stack2.push(6) test_cmp(stack1.__str__(), "<Stack: __stack = [1, 2, 3, 4, 5], __size = 5>", end_=", ") test_cmp(stack2.__str__(), "<Stack: __stack = [1, 2, 3, 4, 5, 6], __size = 6>")

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 23

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

# Testing that is_empty() returns false on a non-empty stack. print("Testing that is_empty() returns false on a non-empty stack... ", end="") test_cmp("is_empty() returned {}".format(stack1.is_empty()), "is_empty() returned False")

# Testing that is_empty() returns true on an empty stack. print("Testing that is_empty() returns true on an empty stack... ", end="") stack1.clear() test_cmp("is_empty() returned {}".format(stack1.is_empty()), "is_empty() returned True")

# Testing that clear() empties the stack. print("Testing that clear() empties the stack... ", end="") test_cmp(stack2.__str__(), "<Stack: __stack = [1, 2, 3, 4, 5, 6], __size = 6>", end_=", ") stack2.clear() test_cmp(stack2.__str__(), "<Stack: __stack = [], __size = 0>")# If we are invoked as a script, call test() to perform testing. If we are invoked as a module, do nothing.if __name__ == "__main__": test()

When stack.py is executed as a script, the __name__ attribute will be "__main__" so test() will be called to performtesting of the Stack class, e.g.,

$ python3 stack.pyTesting constructor function Stack()... passTesting push(int)... passTesting push(list)... passTesting push(tuple)... passTesting push(string)... passTesting push_iterable(list)... passTesting push_iterable(tuple)... passTesting push_iterable(string)... passTesting peek() -> element... passTesting peek() -> sequence... passTesting pop(n=1)... pass, passTesting pop(n=3)... pass, passTesting size() on a non-empty stack... passTesting size() on an empty stack... passTesting shallow copy by assignment... pass, passTesting deep copy by calling copy.deepcopy()... pass, passTesting that is_empty() returns false on a non-empty stack... passTesting that is_empty() returns true on an empty stack... passTesting that clear() empties the stack... pass, pass

On the other hand, when the Stack module is imported into another module, the __name__ attribute will be "Stack" sotest() will not be called but the Stack class and its instance methods will be available.

3.10 A Queue Data StructureSee [1]. A queue is a FIFO data structure and queues are commonly used in programming. The two standard queue opera -tions for adding an element to the queue and removing an element from the queue are called enqueue and dequeue. ThePython list type is not suitable for implementing a queue because while list.pop()—aka enqueue—is O(1), list.insert()—aka dequeue—is O(n), which is too slow. Fortunately, the Python Standard Library has class named deque (pronounced"deck") which is in the collections module. The name deque is short for double-ended queue. The deque type permitsenqueue and dequeue operations from either queue end in O(1) time. To use deque as a standard single-ended queue, wecan choose to enqueue at the left end and dequeue from the right end. Examples,

>>> from collections import deque

>>> q = deque() q is empty.>>> q.appendleft(1) q is [1].>>> len(q)1

>>> q.appendleft(2) q is [2, 1] where 1 is at the front of the queue.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 24

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

>>> q.appendleft(3) q is [3, 2, 1] where 1 is at the front of the queue.>>> len(q)3

>>> n = q.pop() n is 1, q is [3, 2] where 2 is at the front of the queue.>>> len(q)2

>>> n = q.pop() n is 2, q is [3] where 3 is at the front of the queue.>>> n = q.pop() n is 3, q is [] and is now empty>>> len(q)0

Familiarize yourself with these deque class methods,

append(x) Add element x to the right side of the deque.appendleft(x) Add element x to the left side of the deque.clear() Removes all elements from the queue so it becomes empty.copy() Create a shall copy of the deque.count(x) Return the number of occurrences of x.extend(iter) Iterates over the elements of iter, adding each element to the right end of the deque.extendleft(iter) Iterates over the elements of iter, adding each element to the left end of the deque.pop() Remove and return the element from the right side of the deque.popleft() Remove and return the element from the left side of the deque.remove(x) Remove the first occurrence of x starting from the left end.reverse(x) Reverse the elements of the deque in-place.

A deque is a sequence data type, so len(d) will return the number of elements in d. Deque assignment, e.g., deque1 =deque2 will perform a shallow copy. Use copy.deepcopy() to perform a deep copy. A deque is iterable, so for i in d: ...would iterate over each element i of deque d.

References1. Python Std. Lib. - §8.3.3 Deque: https://docs.python.org/3/library/collections.html#collections.deque

3.11 More on TuplesSee [1, 2]. The tuple data type is an immutable, indexable, sequence type consisting of one or more objects (often hetero-geneous) separated by commas, with tuple literals being written as a pair of parentheses surrounding the tuple objects,e.g., t = (1, 2, 3), makes t a 3-tuple consisting of elements 1, 2, and 3. Tuple examples,

>>> t = tuple() t is a new, empty tuple.>>> t = () t is also a new, empty tuple.>>> t = (1, 2, 3) t is a 3-tuple, the elements are 1, 2, and 3.>>> type(t) Prints the type of t.<class 'tuple'>

>>> t = (1) You might think this would create a 1-tuple containing 1, but it does not, rather>>> type(t) (1) evaluates to the integer 1.<class 'int'>

>>> t = (1,) To create a 1-tuple, write a comma following the element.>>> type(t)<class 'tuple'>

>>> t = 1, () can be eliminated, the interpreter still knows we want to create a tuple so it>>> type(t) packs 1 forming the tuple: (1)<class 'tuple'>

>>> t = 1, 2, 3 Again, () can be eliminated and the interpreter will pack 1, 2, and 3

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 25

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

>>> type(t) forming the tuple: (1, 2, 3).<class 'tuple'>>>> t(1, 2, 3)

>>> a, b, c = t Unpacks t and assigns the 3 elems of t to a, b, and c.>>> a, b = t If there are fewer variables than tuple elements, a ValueError exception occurs.Traceback...

...ValueError: ...

>>> len(t) tuple is a sequence type, so the built-in len() function returns the number of elems of t.3

>>> t[0] tuple is an indexable sequence type so we can access the individual elements.1 using subscripts>>> t[2]3

>>> t = ((1, 2), (3, 4)) Creates nested tuples, t is a 2-tuple with two elements: (1, 2) and (3, 4).>>> t[0](1, 2)

>>> t[0][0] Use two subscripts to access the individual ints in the nested tuples.1>>> t[0][1]2>>> t[1][1]4

>>> t = ([1, 2], [3, 4]) t is a 2-tuple containing two lists as elements.>>> t[1][0] Since lists and tuples are both indexable, we can access the list elements this way.3

>>> for item in t: tuple is an iterable data type so we can iterate over the elements of t.print(item)

[1, 2][3, 4]

>>> t[0] = [5, 6] tuples are immutable, a TypeError exception will occur if an attempt to change t is made.Traceback...

...TypeError:...

>>> t = ([1, 2], [3, 4], [5, 6], [7, 8]) Since tuple is a sequence type, elements may be accessed using slices.>>> t[1:3]([3, 4], [5, 6])

References1. Python Tutorial - §5.3 Tuples and Sequences: https://docs.python.org/3/tutorial/datastructures.html2. Python Std. Lib. - §4.6.5 Tuples: https://docs.python.org/3/library/stdtypes.html

3.12 More on SetsA set is an unordered, mutable, nonindexable, iterable collection type, in which the elements of the set must be unique.Set examples,

>>> s = set() s is a new, empty set.>>> s = {1, 2, 3} s is a homogeneous set containing three elements, all ints.>>> s Print the value of s.{1, 2, 3}

>>> s = {1, 2, 3, 3, 2, 1} s is a still a set containing three elements because only unique values are stored.>>> s Print the value of s.{1, 2, 3}

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 26

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

>>> s = {} You might think that this creates a set named s but it actually creates a dict named s.>>> t = {1, 3.1, "Fred"} t is a heterogeneous set containing three elements, an int, a float, and a string.>>> s[0] = 22 sets are nonindexable so using the subscript operator will cause a TypeError exception.Traceback

...TypeError: ...

>>> 1 in s The in and not in membership operators may be used to determine if a value is in a set.True>>> 99 in sFalse>>> 2 not in sFalse

>>> for x in s: print(x) set is iterable; elements are commonly accessed in an iterator loop.12

>>> len(s) set is a collection type, so the length of the set can be found using len().3

>>> s.isdisjoint(t) isdisjoint() returns true if s and t have no elements in common.False False since {1, 2, 3} and {1, 3.1, "Fred"} have 1 in common so s and t are not disjoint.>>> s <= t True if s is a subset of t, i.e., if all of the elements in s are also in t.False False since 2 and 3 are in s but not in t.>>> t = {1, 2, 3, 4, 5} Change t so s is subset of t.>>> s <= t True now since {1, 2, 3} is a subset of {1, 2, 3, 4, 5}.True

>>> s < t True if s is a proper subset of t, i.e, if s is a subset of t but s does not equal t.True True since {1, 2, 3} is a subset of {1, 2, 3, 4, 5} and s and t are not equal.>>> s = {1, 2, 3, 4, 5} Change s so s equals t.>>> s <= t True since s = {1, 2, 3, 4, 5} is a subset of t = {1, 2, 3, 4, 5}.True

>>> s < t False since s is a subset of t but s equals t.False

>>> s >= t True since s = {1, 2, 3, 4, 5} is a superset of t = {1, 2, 3, 4, 5}, i.e., t is a subset of s.True

>>> s > t False since s = {1, 2, 3, 4, 5} is a superset of t but s and t are equal.False

>>> s == t True since s = {1, 2, 3, 4, 5} equals t = {1, 2, 3, 4, 5}True

>>> s != t False since s = {1, 2, 3, 4, 5} equals t = {1, 2, 3, 4, 5}False

>>> s = {1, 2, 3} Change s.>>> s & t Forms the intersection of s and t, i.e., the set that consists of common elements.{1, 2, 3} {1, 2, 3} {1, 2, 3, 4, 5} is {1, 2, 3}∩>>> s = {'a', 'b'} Change s.>>> t = {1, 2, 3} Change t.>>> s | t Forms the union of s and t, i.e., the set that consists of all elements from s and t.{'a', 1, 2, 3, 'b', 'c'} {'a', 'b', 'c'} {1, 2, 3} is {'1', '2', '3', 'a', 'b', 'c'}. Note that sets are unordered.∪>>> s = {1, 2, 3} Change s.>>> t = {1, 2, 3, 4, 5} Change t.>>> s - t Forms the difference of s and t, i.e., the set that consists of all elements from s set() minus the common elements of s and t. Interpreter prints set() when the set is empty.>>> t - s Forms the difference of t and s, i.e., the set that consists of all elements from t{4, 5} minus the common elements of s and t.>>> x = s x and s now refer to the same set {1, 2, 3}.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 27

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

>>> x.add(4) Add 4 to set x. Since x and s refer to the same set, s = x = {1, 2, 3, 4}>>> s{1, 2, 3, 4}>>> x{1, 2, 3, 4}

>>> x.remove(4) Remove 4 from x. x and s still refer to the same set, so s = x = {1, 2, 3}.>>> s{1, 2, 3}>>> x{1, 2, 3}

>>> s.remove(99) A KeyError exception occurs if the set element does not exist.Traceback: ...

...KeyError: 99

>>> s.update(t) update() modifies s to include all of the non-common elements of t.>>> s Note that s |= t is equivalent to s.update(t).{1, 2, 3, 4, 5}>>> s = {1, 2, 3}>>> t = {2, 3, 4, 5}

>>> s.intersection_update(t) intersection_update() modifies s to include only the elements common to s and t.>>> s Note that s &= t is equivalent to s.intersection_update(t).{2, 3}>>> s = {1, 2, 3}

>>> s.difference_update(t) difference_update() modifies s to remove elements found in t.>>> s Note that s -= t is equivalent to s.difference_update(t){1}

>>> s.discard(1) discard() is like remove(), but it does not raise an exception if the element does not exist.>>> s Removed 1 from {1} so s is now empty.set()

>>> t Print t.{2, 3, 4, 5}

>>> t.clear() clear() removes all elements from the set, making it empty.>>> tset()

>>> s = {1, 2, 3} Initialize s.>>> x = copy.deepcopy(s) Make x a deep copy of s, i.e., s and x refer to different set objects.>>> x.add(4) Adding 4 to x does not modify s.>>> s

{1, 2, 3} Notice that s was unchanged when 4 was added to x.>>> x

{1, 2, 3, 4} x was, of course, changed.

References1. Python Tutorial - §5.4 Sets: https://docs.python.org/3/tutorial/datastructures.html#sets2. Python Std. Lib. - §4.9 Set Types: https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset

3.13 C-Like StructuresSuppose in C we wish to represent Cartesian coordinates using a structure to store the x and y coordinates,

typedef struct { // point is equivalent to struct { int x; int y}int x;int y;

} point;

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 28

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

point p1; // Define a point variable named p1.p1.x = 10; // Set p1's x data member to 10.p1.y = 20; // Set p1's y data member to 20.printf("%d\n", p1.x + p1.y); // Displays 30.p1.x = p1.y; // Change p1's x data member to be the same as y.printf("%d\n", p1.x + p1.y); // Displays 40.

Python does not have a built-in structure type, nor does it have a class in the library for creating structures. According tothe Stack Overflow page [1], there are various ways of simulating C-like structures. To me, the easiest and cleanest way isto simply create a class that has instance variables corresponding to the data members of the C struct.

class Point(object): # Point is a new class derived from object (Python convention caps class name)def __init__(self):

self.x = 0 # Create a data member named x initialized to 0.self.y = 0 # Create a data member named y initialized to 0.

p1 = Point() # Create a new point object named p1.print(p1.x, p1.y) # Displays 0 0p1.x = 10 # Change the value of the x data memberp1.y = 20 # Change the value of the y data memberprint(p1.x, p1.y) # Displays 10 20

Later, if we need to augment our Point class to represent 3D points, we just modify the class,

class Point(object):def __init__(self):

self.x = 0self.y = 0self.z = 0 # Add a new member.

p1 = Point()print(p1.x, p1.y, p1.z) # Displays 0 0 0p1.x = 10p1.y = 20p1.z = p1.x + p1.yprint(p1.x, p1.y, p1.z) # Displays 10 20 30

Alternatively, if one wants to require the structure data members to be initialized when the Point object is created, we canwrite the __init__() function so it essentially acts as a constructor,

class Point(object): # Define a new class named Point.def __init__(self, p_x, p_y): # __init__ is like a ctor (self is like this in C++/Java).

self.x = p_x # self.x is a data member initialized to parameter p_x.self.y = p_y # self.y is a data member initialized to parameter p_y.

p = Point() # Error: must pass initial values for x and i.p = Point(10, 20) # Create a Point object named p with p.x = 10, p.y = 20.print(p.x, p.y) # Displays 10 20p.x = p.y # Change p.x to 20print(p.x, p.y) # Displays 20 20

Others on the Stack Overflow webpage go on to discuss alternative ways. Suggestions include the namedtuple class fromthe collections module, which creates a standard tuple where the values can be referenced by names, e.g.,

from collections import namedtuple # Import collections.namedtuple class.Point = namedtuple("Point", "x y") # Create a namedtuple class named Point with x, y data members.p = Point(x = 10, y = 20) # Create a new Point object initializing x and y.print(p.x, p.y, p[0], p[1]) # Displays 10 20 10 20

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 29

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

Note that one advantage of namedtuple objects is that the data members can be accessed by name or by an index; theycan also be iterated over,

for q in p:print(q) # Displays 10 on the first pass (q is p.x) and 20 on the second pass (q is p.y).

You cannot index or iterate over the elements of the Point class defined above. The major problem I see with namedtuple(and there may be an elegant workaround with which I am unfamiliar) is that the syntax for changing the value of a datamember is nasty—because tuples and namedtuples are immutable,

p.x = 20 # Change x to 20? No, AttributeError exception: "can't set attribute".p._replace(x = 20) # Creates a new Point namedtuple object with x = y = 20.print(p.x, p.y, p[0], p[1]) # Displays 10 20 10 20 rather than 20 20 20 20

The above code does not work because _replace() does not modify p, it returns a new namedtuple object. Thus we have toresort to,

p = p._replace(x = 20)

Now that is beyond ugly and there is no way I am going to write code like that. The next Stack Overflow suggestion is tocreate a Point class and add the data members and their values to the default dictionary that every object contains,

class Point(object): # Create a new class named Point derived from object.def __init__(self, **kwargs): # __init__() is like a ctor

self.__dict__.update(kwargs) # Add the keyword args passed to __init__() to the default dict.

p = Point(x = 10, y = 20) # Create a Point object named p initializing p.x and p.y.print(p.x, p.y) # Displays 10 20p.x = p.y # Changes p.x to 20print(p.x, p.y) # Displays 20 20

Hmm, that syntax is not too bad (other than the complete ugliness that is required to create the point class but just copy-and-paste it). One downside is that unlike the namedtuple method, we cannot index the data members of the point object,

p[0] = 20 # Change x to 20? No, this is syntactically incorrect

nor can we iterate over them. But then again, with C structs, you cannot index the data members either. One advantageof this "update the default dictionary" method is that we can easily add new data members,

print(p.x, p.y, p.z) # AttributeError: 'point' object has not attribute 'z'p.z = 30print(p.x, p.y, p.z) # Displays 20 20 30

That's pretty cool and does exactly what I would like a structure object to do. Finally, some on Stack Overflow advocateusing a dictionary,

p = {'x': 10, 'y': 20} # Create a Point object with 'x' and 'y' as data member names.print(p.x, p.y) # Nope, syntactically incorrect.print(p['x'], p['y']) # Displays 10 20 but this code is not pretty.p['x'] = p['y'] # Change 'x' to 20.print(p['x'], p['y']) # Displays 20 20 but the code is still horrendously ugly.

What I dislike most about this method is that the data members (the keys of the dictionary) cannot simply be x and y,they have to be the strings 'x' and 'y'. This leads to nasty syntax for accessing the data members. Python dictionariesseem to me to be a bad choice for implementing a C-like struct. Out of all of my choices, I prefer the "update the defaultdictionary" method.

References1. Stack Overflow: http://stackoverflow.com/questions/35988/c-like-structures-in-python

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 30

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

3.14 ClassesTo create a class we must write a class definition statement, with this syntax,

class class-name(superclass-name):statement1

statement2

...

statement

The statements are commonly function definition statements, but can include other types of statements as well, e.g.,

# Fraction.pyclass Fraction(object):

def __init__(self, num, den):self._num = num # _varname is Python-speak for protected. _varname can be accessed in subclasses.self._den = den # __varname is Python-speak for private. __varname cannot be accessed in subclasses.

def add(self, f2): num = self._num * f2._den + self._den * f2._num den = self._den * f2._den return Fraction(num, den)

# Not all statements in a class definition have to be function definitions. However, these statements# are only executed once: when the class definition is compiled to create the Fraction class object.class_var = -1 # Simulates a class variable which is shared among all objects.print(class_var) # Note: this statement is also only executed once when Fraction is compiled.

Classes are created (compiled) at run-time when the class definition statement of a module is reached as the interpre-ter is reading the module or script. The result from compiling a class is a class object, e.g.,

# At this time, Fraction is a class object, i.e., in Python classes are objects. An instance object is# like a regular object in C++ and Java. Create three Fraction instance objects: f1, f2, and sum.

f1 = Fraction(1, 3) # Creates a Fraction instance object with f1.num = 1 and f1.den = 3.f2 = Fraction(3, 5) # Creates another Fraction instance object with f2.num = 3 and f2.den = 5.sum = f1.add(f2) # Calls f1.add() passing f2 as the argument. A Fraction object is returned.

Attributes are identifiers following the dot operator, e.g., f1._num is an attribute reference to a data attributenamed _num (which is an integer). Data attributes are the same as instance variables in Java and data members inC++. The other type of attribute is a method. A method is a function definition that "belongs" to the object. The term"method" is used with other object types, i.e., objects that are not class instance objects. Consequently, f1.add() is anattribute reference to a (class) method object. To confuse things more, Fraction.add is a function object and acts likea function pointer in C and C++.

A method attribute reference, e.g., sum = f1.add(f2) is equivalent to sum = Fraction.add(f1, f2).

Class operations: class objects (essentially, the class definition) support two kinds of operations: attribute referencesand instantiation. The syntax of an attribute reference (whether to a data attribute or to a function object) is,

obj-name.attribute-name

For example, f1._num, f1._den, Fraction.__init__, and Fraction.add are all valid attribute references. The first two areattribute references to data attributes of f1. The latter two do not call the functions, but rather return function objects(more on function objects in a bit).

Class instantiation takes place by calling a class object and uses function notation, e.g., f1 = Fraction(10, 20) creates anew instance of Fraction, and as mentioned above, f1 is an instance object.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 31

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

The special instance method __init__() (you should never write a function in Python that starts and ends with __; thisnotation is reserved for special language-specific functions) is called after an instance object is instantiated. The job of__init__() is to initialize the instance object, generally by creating and initializing the object's data attributes. The firstargument to __init__() is a reference to the instance object being initiated, and conventionally, this argument is namedself (self is like this in C++ and Java). As shown in Fraction.__init__(), __init__() can have additional arguments,but self must be the first one. Note: we never explicitly pass self as an argument to __init__() and the other classmethods: the Python interpreter will automatically include self in the call.

Instance objects: the only operation understood by instance objects are attribute references which are either referencesto data attributes, e.g., f1._num, or methods, e.g., f1.add(f2).

Method objects: a method is "bound" by writing something like obj-name.method-name(...) and is usually calleddirectly thereafter. However, in x = Fraction.add (note the missing parentheses), x is bound to method object Fraction.add() but it not directly called. For example,

def main():f1 = Fraction(1, 3) # f1 is a Fraction instance object.f2 = Fraction(3, 5) # f2 is a Fraction instance object.ref_add = Fraction.add # ref_add is a function object, referring to Fraction.add.sum = foo(f1, f2, ref_add) # Illustrates that function objects can be passed as args.

def foo(a, b, f):return f(a, b) # Since f refers to Function.add this is essentially performing return a.add(b)

Class and instance variables: An instance variable (properly, an instance data attribute) is created in the instanceobject for each instance object that is instantiated. A class variable (properly, a class data attribute) "belongs" to theclass and is shared among all instance objects of the class. For example, in Fraction, class_var is a class data attributesince it is defined within the Fraction class definition but outside the function definition statements of the Fraction class.All Fraction instance objects share class_var, e.g.,

import Fraction

def main: f1 = Fraction(1, 3) # f1 is a Fraction instance object. print(f1, sep=" ", end="") # Invokes print(f1.__str__()). print(" class_var = ", f1.class_var) # Prints -1 since Fraction.class_var was initialized to -1. Fraction.class_var = 99 # Change Fraction.class_var from -1 to 99. print("class var = ", f1.class_var) # Prints 99 since Fraction.class_var has changed. f2 = Fraction(3, 5) # f2 is a different Fraction instance object.

print("f1.class var = %d, f2.class_var = %d" % (f1.class_var, f2.class_var)) # Prints 99 99

Note that class data attributes must be changed by writing class-name.class-attrib = new-value and not by instance-obj.class-attrib = new-value. Continuing from above,

def main:...print("f1.class var = %d, f2.class_var = %d" % (f1.class_var, f2.class_var)) # Prints 99 99f1.class_var = 100print("f1.class var = %d, f2.class_var = %d" % (f1.class_var, f2.class_var)) # Prints 100 99print("Fraction.class_var = %d" % (Fraction.class_var)) # Prints 99 99

When f1.class_var was assigned 100, this created a new instance data attribute named class_var within the f1 instanceobject, so now f1.class_var is 100 but Fraction.class_var is still -1. Furthermore, f2.class_var still refers to the same valueas Fraction.class_var, so printing f2.class_var will still print 99.

Random remarks: Data attributes override methods with the same name, e.g., a data attribute named num mightconflict with a class function named num(). There are a couple of acceptable solutions to solve this problem: (1) do not

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 32

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

define a method with the same name as a data attribute, or vice versa; or (2) prefix data attributes or method names witha unique identifier, for example m_num, and m_den for data attributes for the numerator and denominator and methodnames num() and den() for accessor functions for the data members.

The reference to the object self is named "self" by convention. We could name it this, or something else, if we felt morecomfortable doing that. However, self is well-engrained in the Python community, so don't do that.

Each value (integer, real number, list, etc) in Python is an instance object and therefore has a class (also called its type).

The type of the object can be determined by calling the type() built-in function. For example, type(7) is <class 'int'>. Thetype is stored in a special class variable named __class__, e.g., if f1 is a Fraction instance object, then type(f1) is <class'__main__.Fraction'> and f1.__class__ is also <class '__main__.Fraction'>.

References1. Python Tutorial - §9 Classes: https://docs.python.org/3/tutorial/classes.html

4 The Python Standard LibraryLike many other high-level programming languages, Python has a fairly large Standard Library, see [1].

References1. Python Standard Library: https://docs.python.org/3/library/index.html

4.1 Shallow and Deep Copies: The copy ModuleAssignment statements do not copy objects; rather, they create a binding between an identifier and the object. Example,

>>> L1 = [1, 2, 3]>>> L2 = [4, 5, 6]>>> print(L1, L2)[1, 2, 3][4, 5, 6]

>>> L2 = L1 L2 and L1 refer to the same list, so L2 is a shallow copy of L1.>>> print(L1, L2)[1, 2, 3][1, 2, 3]

>>> L2[0] = 9 Any changes to L2 will also change L1 since they refer to the the same object.>>> print(L1, L2)[9, 2, 3][9, 2, 3]

Making a deep copy of an object, will cause a new object to be created so the original object and the new object willrefer to different values. To make a deep copy, we use the copy.deepcopy() function of the copy module.

>>> from copy import deepcopy We can refer to copy.deepcopy() as just deepcopy().>>> L1 = [1, 2 ,3]>>> L2 = [4, 5, 6]>>> print(L1, L2)[1, 2, 3][4, 5, 6]

>>> L2 = deepcopy(L1) L2 becomes a deep copy of L1 so they refer to different lists.>>> print(L1, L2)[1, 2, 3][1, 2, 3]

>>> L2[0] = 9 Changes to L2 do not affect L1 since they refer to different lists.>>> print(L1, L2)[1, 2, 3][9, 2, 3]

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 33

CSE294 Algorithmic Problem Solving Course Notes :: Introduction to Python (Rev 1.4)

References1. Python Std. Lib. - §8.10 The copy Module: https://docs.python.org/3/library/copy.html

4.2 The decimal ModuleThe decimal module provides support for exact real numbers with an arbitrary number of digits after the decimal point.Examples,

>>> import decimal>>> getcontext().prec = 30

>>> print(Decimal(1) / Decimal(7)) Prints 1 / 7 with 30 digits of precision.0.142857142857142857142857142857>>> getcontext().prec = 50

>>> print(Decimal(13).sqrt()) Prints sqrt(13) with 50 digits of precision.3.6055512754639892931192212674704959462512965738452

References1. Python Std. Lib. - §9.4 The decimal Module: https://docs.python.org/3/library/decimal.html

Revision InformationRev 1.0 - 16 Jan 2016Original release.

Rev 1.1 - 20 Jan 2016.Corrected minor types on pp. 5, 6. Added "Dict displays" to the list of atoms on p. 5. Explained how to create a tuple with one value on p. 5. Added a discussion of the global variable __name__ on p. 9.

Rev 1.2 - 17 Feb 2016Added a discussion of C-like structures in Sect 3.12.

Rev 1.3 - 12 Sep 2016Rewrote the entire document, adding new material and editing existing material to make it more readable.

Rev 1.4 - 22 Jan 2017Minors edits to improve clarity or correct mistakes.

(c) Kevin R. Burger :: Computer Science & Engineering :: Arizona State University Page 34