Math 480 Lecture 5:


Lists, Tuples, Strings and Files

Lists

A list in Python is a finite ordered "list" of any Python objects at all.    Many useful operations are supported, along with a handy "list comprehension" notation that makes building lists easy. 

First we create a list, whose entries are an integer, a string, a data type, and another list with a list in it.  Note that v has type 'list'.

{{{id=13| v = [3, 'hello', Integer, ['a', [1,2]]] type(v) /// }}} {{{id=12| v /// [3, 'hello', , ['a', [1, 2]]] }}}

Lists in Python are 0-based, in that v[0] is the first entry in the list.  Remember this!

{{{id=14| v[0] /// 3 }}} {{{id=15| v[1] /// 'hello' }}}

You can also index into the list from the other side by using negative numbers:

{{{id=19| v[-1] /// ['a', [1, 2]] }}} {{{id=21| v[-2] /// }}}

You can slice lists.   When slicing you specify a start and stop point, and take all the elements between. Keep in mind that it includes the starting point you specify, but excludes the endpoint.

{{{id=24| v[1:] /// ['hello', , ['a', [1, 2]]] }}} {{{id=25| v[0:3] /// [3, 'hello', ] }}} {{{id=26| v[0:3:2] # just the even-indexed positions /// [3, ] }}}

Use len to get the length of a list.  New Sage/Python users often get frustrated trying to figure out how to find the length of a list.  Just memorize this right now: len!

{{{id=16| len(v) /// 4 }}}

You can also sort, append to, delete elements from, extend, etc., lists.  See the Python documentation.  

{{{id=31| w = copy(v) w.sort(); w /// [3, ['a', [1, 2]], 'hello', ] }}} {{{id=28| w.extend([1,2,3,4]); w /// [3, ['a', [1, 2]], 'hello', , 1, 2, 3, 4] }}} {{{id=32| /// }}}

You can build lists in place using list comprehension, which is a lot like "set building notation" in mathematics.  For example:

{{{id=17| [n*(n+1)/2 for n in range(1, 10) if n%2 == 1] /// [1, 6, 15, 28, 45] }}}

The structure is:   [ <expression(var)>   for  var in <iterable> ] and an optional if condition.

Notice above that "for n in range(1,10)" and "if n%2==1" are both valid snippets of Python code.   List comprehensions are equivalent to for loops with an if statement in them, where you append to a list, and you can literally almost rearrange the code of such a for loop into a list comprehension!

{{{id=36| z = [] for n in range(1, 10): if n % 2 == 1: z.append(n*(n+1)/2) z /// [1, 6, 15, 28, 45] }}}

If you want to be effective with Sage/Python, you must absolutely and completely master lists. 

{{{id=71| /// }}}

Tuples

Tuples are pretty similar to lists, except you can't change which objects are stored in a tuple.   Also, there is no tuple-comprehension; you have to make a list v, then change it into a tuple by typing tuple(v). You can however, change the objects themselves if they are mutable. 

{{{id=74| v = (3, 'hello', Integer, ['a', [1,2]]) type(v) /// }}} {{{id=72| v[0] = 5 # nope! /// Traceback (most recent call last): File "", line 1, in File "_sage_input_83.py", line 10, in exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("dlswXSA9IDUgICMgbm9wZSE="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single') File "", line 1, in File "/tmp/tmpRlXBXR/___code___.py", line 3, in exec compile(u'v[_sage_const_0 ] = _sage_const_5 # nope!' + '\n', '', 'single') File "", line 1, in TypeError: 'tuple' object does not support item assignment }}} {{{id=75| v[3].append('change a mutable entry') v /// (3, 'hello', , ['a', [1, 2], 'change a mutable entry']) }}}

WARNING: The following looks like a tuple comprehension, but it isn't one:

{{{id=77| w = (n*(n+1)/2 for n in range(1, 10) if n%2 == 1) w /// at 0x423b780> }}} {{{id=76| type(w) /// }}} {{{id=79| w[0] /// Traceback (most recent call last): File "", line 1, in File "_sage_input_4.py", line 10, in exec compile(u'open("___code___.py","w").write("# -*- coding: utf-8 -*-\\n" + _support_.preparse_worksheet_cell(base64.b64decode("d1swXQ=="),globals())+"\\n"); execfile(os.path.abspath("___code___.py"))' + '\n', '', 'single') File "", line 1, in File "/tmp/tmpllbip2/___code___.py", line 3, in exec compile(u'w[_sage_const_0 ]' + '\n', '', 'single') File "", line 1, in TypeError: 'generator' object is unsubscriptable }}}

The above is an example of a generator, which is something you can iterate over.  It doesn't use much memory, and the expression isn't evaluated until you explicit start iterating over it.

{{{id=81| for n in w: print n, /// 1 6 15 28 45 }}}

Here, we get no output since w is "used up".

{{{id=83| for n in w: print n, /// }}}

Anyway, if you want to make a tuple using a list comprehension, be explicit, like so:

{{{id=86| tuple( n*(n+1)/2 for n in range(1, 10) if n%2 == 1 ) /// (1, 6, 15, 28, 45) }}} {{{id=34| /// }}}

Strings

A string is a finite immutable (unchangeable) sequence of characters.   Python supports a wonderful range of string processing functions.    To make a string literal:

  • Enclose it is in either single or double quotes (just be consistent) -- if you use single quotes you can use double quotes in your string without escaping them, and vice versa.
  • For a multiline string use three single or double quotes in a row -- then you can include newlines directly in your string.
  • There are many escape characters for including special characters in strings, e.g., '\n' for 'newline'.  If you put the letter r right before the quotes you get a raw string, for which a backslash just stays a backslash you can't escape anything; this is often useful for LaTeX code. 

The following examples illustrates some of the above ways of creating strings.

{{{id=42| s = "this is a string's string using double quotes" s /// "this is a string's string using double quotes" }}} {{{id=41| print s /// this is a string's string using double quotes }}} {{{id=40| s = 'this is a string"s using single quotes' s /// 'this is a string"s using single quotes' }}} {{{id=43| s = """this is a multiline string.""" s /// 'this is a \nmultiline string.' }}} {{{id=39| print s /// this is a multiline string. }}} {{{id=44| s = r"""Consider \sin(x) + \cos(y) and add \pi.""" print s /// Consider \sin(x) + \cos(y) and add \pi. }}}

Strings in Python are extremely flexible and easy to manipulate.  You can slice them exactly like lists, find substrings, concatenate, etc.

{{{id=46| s = "This is a string." s[:10] /// 'This is a ' }}} {{{id=45| s[10:] /// 'string.' }}} {{{id=3| s[::2] # get just the even indexed characters /// 'Ti sasrn.' }}} {{{id=51| s.find('a') /// 8 }}} {{{id=50| s + " Yes, a string." /// 'This is a string. Yes, a string.' }}} {{{id=49| s.replace('a', 'b') /// 'This is b string.' }}}

The join method is also amazingly useful.    If s is a string, then s.join([list of strings]) joins together the list of strings putting s between each.

{{{id=54| ', '.join(['Stein', 'William', 'Arthur']) /// 'Stein, William, Arthur' }}}

Other useful methods are upper and capitalize:

{{{id=52| s = 'this is lower case' s.upper() /// 'THIS IS LOWER CASE' }}} {{{id=55| s.capitalize() /// 'This is lower case' }}}

Finally, the string formating operator % appears constantly in Python code and is extremely useful to know about.   Basically, you just put %s's in your string, and these get replaced by the string representations of a tuple of Python objects.   Here's how you use it:

{{{id=59| 'Hi %s. Meet %s.'%('Mom', 2/3) /// 'Hi Mom. Meet 2/3.' }}}

Really what just happened was we created a string and a tuple, and used the mod operator on them, as illustrated below.

{{{id=56| s = 'Hi %s. Meet %s.' t = ('Mom', 2/3) s % t /// 'Hi Mom. Meet 2/3.' }}}

There are many other formating options besides just %s.  E.g., %f is useful for numerical computations.

{{{id=62| '%.2f %.3f'%(.5, 7/11) /// '0.50 0.636' }}}

Above, %.2f formats the string with 2 decimal digits after the point, and %.3f with 3 decimal digits.

{{{id=63| /// }}}

Files

It is usually straightforward to open, read, write, append to, and close files on disk.  For example, below we create a file foo, write to it, cose it, open it, then read it.

{{{id=66| F = open('foo','w'); print F F.write('hello there') F.close() print open('foo').read() /// hello there }}}

In the Sage notebook each input cell is executed in a different directory.  Thus if you just create a file in one cell, you can't easily open and read it in another cell.  There best workaround is to use the DATA variable, which is a common directory that all cells have access to, and which you can upload/download files to and from using the Data menu above. 

{{{id=48| open(DATA + 'foo','w').write('hi') /// }}} {{{id=68| print open(DATA + 'foo').read() /// hi }}} {{{id=69| os.system('ls -l %s'%DATA) /// total 4 -rw-r--r-- 1 sagenbflask sagenbflask 2 2011-04-06 11:35 foo 0 }}} {{{id=70| print DATA /// /sagenb/flask/sage_notebook.sagenb/home/openidSfmMv1OuVE/17/data/ }}} {{{id=2| /// }}} {{{id=8| /// }}} {{{id=1| /// }}}