Python Demo#

UW Geospatial Data Analysis
CEE467/CEWA567
David Shean

Overview#

Quick set of interactive examples to illustrate a few key aspects of Python and iPython.
Emphasis on concepts needed for lab exercises.

Tentative discussion topics#

  • Importing modules

  • Indentation

  • Variables

    • (don’t use “list” as a variable name)

  • Strings, formatting

  • Quoting

  • Tuples, lists, dictionaries

  • 0 vs. 1 as first index

  • List comprehension

  • Indexing

  • Functions

  • Objects, classes - attributes and methods

  • Interpreting error/warning messages

Topics for later#

  • Main and doc strings

Import modules#

import os
os?
Type:        module
String form: <module 'os' from '/srv/conda/envs/notebook/lib/python3.9/os.py'>
File:        /srv/conda/envs/notebook/lib/python3.9/os.py
Docstring:  
OS routines for NT or Posix depending on what system we're on.

This exports:
  - all functions from posix or nt, e.g. unlink, stat, etc.
  - os.path is either posixpath or ntpath
  - os.name is either 'posix' or 'nt'
  - os.curdir is a string representing the current directory (always '.')
  - os.pardir is a string representing the parent directory (always '..')
  - os.sep is the (or a most common) pathname separator ('/' or '\\')
  - os.extsep is the extension separator (always '.')
  - os.altsep is the alternate pathname separator (None or '/')
  - os.pathsep is the component separator used in $PATH etc
  - os.linesep is the line separator in text files ('\r' or '\n' or '\r\n')
  - os.defpath is the default search path for executables
  - os.devnull is the file path of the null device ('/dev/null', etc.)

Programs that import and use 'os' stand a better chance of being
portable between different platforms.  Of course, they must then
only use functions that are defined by all platforms (e.g., unlink
and opendir), and leave all pathname manipulation to os.path
(e.g., split and join).
os.path?
Type:        module
String form: <module 'posixpath' from '/srv/conda/envs/notebook/lib/python3.9/posixpath.py'>
File:        /srv/conda/envs/notebook/lib/python3.9/posixpath.py
Docstring:  
Common operations on Posix pathnames.

Instead of importing this module directly, import os and refer to
this module as os.path.  The "os.path" name is an alias for this
module on Posix systems; on other systems (e.g. Windows),
os.path provides the same operations in a manner specific to that
platform, and is an alias to another module (e.g. ntpath).

Some of this can actually be useful on non-Posix systems too, e.g.
for manipulation of the pathname component of URLs.
os.path.split?
Signature: os.path.split(p)
Docstring:
Split a pathname.  Returns tuple "(head, tail)" where "tail" is
everything after the final slash.  Either part may be empty.
File:      /srv/conda/envs/notebook/lib/python3.9/posixpath.py
Type:      function
os.path.split??
Signature: os.path.split(p)
Source:   
def split(p):
    """Split a pathname.  Returns tuple "(head, tail)" where "tail" is
    everything after the final slash.  Either part may be empty."""
    p = os.fspath(p)
    sep = _get_sep(p)
    i = p.rfind(sep) + 1
    head, tail = p[:i], p[i:]
    if head and head != sep*len(head):
        head = head.rstrip(sep)
    return head, tail
File:      /srv/conda/envs/notebook/lib/python3.9/posixpath.py
Type:      function

Variable assignment#

p = /srv/conda/envs/notebook/lib/python3.8/posixpath.py
  File "/tmp/ipykernel_521/2673790754.py", line 1
    p = /srv/conda/envs/notebook/lib/python3.8/posixpath.py
        ^
SyntaxError: invalid syntax

Errors and Warnings#

  • The above is an Error

  • Stops execution

  • Read the output from the bottom up (trace can be long)

  • Different than a warning

p = "/srv/conda/envs/notebook/lib/python3.8/posixpath.py"
p
'/srv/conda/envs/notebook/lib/python3.8/posixpath.py'

Quotes#

p = '/srv/conda/envs/notebook/lib/python3.8/posixpath.py'
p
'/srv/conda/envs/notebook/lib/python3.8/posixpath.py'

Tuples#

os.path.split(p)
('/srv/conda/envs/notebook/lib/python3.8', 'posixpath.py')
mytuple = os.path.split(p)
mytuple
('/srv/conda/envs/notebook/lib/python3.8', 'posixpath.py')

Basic indexing#

  • Zero-based index

mytuple[0]
'/srv/conda/envs/notebook/lib/python3.8'
mytuple[1]
'posixpath.py'
mytuple[2]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
/tmp/ipykernel_521/2368449210.py in <module>
----> 1 mytuple[2]

IndexError: tuple index out of range
# Try to assign value to first item in tuple
mytuple[0] = 'something different'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_521/1845405818.py in <module>
      1 # Try to assign value to first item in tuple
----> 2 mytuple[0] = 'something different'

TypeError: 'tuple' object does not support item assignment

Variable assignment and types#

a = 0
print(a)
type(a)
0
int
a = 'cool string'
print(a)
type(a)
cool string
str

What’s a str?#

https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str

str?
Init signature: str(self, /, *args, **kwargs)
Docstring:     
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or
errors is specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to sys.getdefaultencoding().
errors defaults to 'strict'.
Type:           type
Subclasses:     DeferredConfigString, _rstr, LSString, include, ColorDepth, Keys, InputMode, CompleteStyle, SortKey
#Lots of methods, explore with tab completion
a.capitalize()
'Cool string'
b = a.upper()
b
'COOL STRING'

String formatting#

f'Here is a {a}'
'Here is a cool string'
f'Here is a {a}, and another: {b}'
'Here is a cool string, and another: COOL STRING'
lon = -121.01234567
f'{lon:.2f}'
'-121.01'

Lists#

a = range(10)
a
range(0, 10)
range?
Init signature: range(self, /, *args, **kwargs)
Docstring:     
range(stop) -> range object
range(start, stop[, step]) -> range object

Return an object that produces a sequence of integers from start (inclusive)
to stop (exclusive) by step.  range(i, j) produces i, i+1, i+2, ..., j-1.
start defaults to 0, and stop is omitted!  range(4) produces 0, 1, 2, 3.
These are exactly the valid indices for a list of 4 elements.
When step is given, it specifies the increment (or decrement).
Type:           type
Subclasses:     
a.start
0
t = tuple(a)
t
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

Built-in functions#

https://docs.python.org/3/library/functions.html

len?
Signature: len(obj, /)
Docstring: Return the number of items in a container.
Type:      builtin_function_or_method
len(t)
10
l = list(a)
l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
l.len()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/tmp/ipykernel_521/2236946988.py in <module>
----> 1 l.len()

AttributeError: 'list' object has no attribute 'len'
len(l)
10

Boolean#

0 in l
True
True?
Type:        bool
String form: True
Namespace:   Python builtin
Docstring:  
bool(x) -> bool

Returns True when the argument x is true, False otherwise.
The builtins True and False are the only two instances of the class bool.
The class bool is a subclass of the class int, and cannot be subclassed.
int(True)
1
i = 'asdf' in l
i
False
int(False)
0

Conditional#

if 5 in l:
    print("It's totally there!")
It's totally there!
if 'asdf' in l:
    print("It's totally there!")
else:
    print("Nope")
Nope

Indexing#

l[2]
2
l[-2]
8
l[-5:-1]
[5, 6, 7, 8]
l[::2]
[0, 2, 4, 6, 8]
l[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
#Operates in place
l.reverse()
l
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
l.sort()
l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Assignment#

#Lists can contain variable object types
l[0] = 'first'
l
['first', 1, 2, 3, 4, 5, 6, 7, 8, 9]
l[2]
2
l[2] = 12
l
['first', 1, 12, 3, 4, 5, 6, 7, 8, 9]
l[2] = l[2] + 1
l
['first', 1, 13, 3, 4, 5, 6, 7, 8, 9]
l[2] += 1
l
['first', 1, 14, 3, 4, 5, 6, 7, 8, 9]

Loops#

for i in l:
    print(i)
first
1
14
3
4
5
6
7
8
9
for n, i in enumerate(l):
    print(n, i)
0 first
1 1
2 14
3 3
4 4
5 5
6 6
7 7
8 8
9 9
#List comprehension
[print(i) for i in l]
first
1
14
3
4
5
6
7
8
9
[None, None, None, None, None, None, None, None, None, None]
l = list(range(10))
l_float = [float(i) for i in l]
l_float
[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
out = [i/2 for i in l]
out
[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5]

Combining objects#

1 + 2
3
1.1 + 2
3.1
'asdf'+'jkl;'
'asdfjkl;'
'asdf'+1
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_521/917225922.py in <module>
----> 1 'asdf'+1

TypeError: can only concatenate str (not "int") to str
'asdf'+str(1)
'asdf1'

Find multiples of a given integer in a list#

  • Find all multiples of 5 in the list of integers between 0 and 100

  • Use the python modulo operator (%) - returns remainder

  • If remainder is 0, the number is a multiple!

l = list(range(100))
l
[0,
 1,
 2,
 3,
 4,
 5,
 6,
 7,
 8,
 9,
 10,
 11,
 12,
 13,
 14,
 15,
 16,
 17,
 18,
 19,
 20,
 21,
 22,
 23,
 24,
 25,
 26,
 27,
 28,
 29,
 30,
 31,
 32,
 33,
 34,
 35,
 36,
 37,
 38,
 39,
 40,
 41,
 42,
 43,
 44,
 45,
 46,
 47,
 48,
 49,
 50,
 51,
 52,
 53,
 54,
 55,
 56,
 57,
 58,
 59,
 60,
 61,
 62,
 63,
 64,
 65,
 66,
 67,
 68,
 69,
 70,
 71,
 72,
 73,
 74,
 75,
 76,
 77,
 78,
 79,
 80,
 81,
 82,
 83,
 84,
 85,
 86,
 87,
 88,
 89,
 90,
 91,
 92,
 93,
 94,
 95,
 96,
 97,
 98,
 99]
result = []
for i in l:
    if i % 5 == 0:
        result.append(i)
result
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]

OK, what about multiples of 7#

result = []
for i in l:
    if i % 7 == 0:
        result.append(i)
result
[0, 7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98]

OK, what about multiples of 10. This is getting old…#

result = []
for i in l:
    if i % 10 == 0:
        result.append(i)
result
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

Create a function#

def find_multiples_list(inlist, n):
    result = []
    for i in inlist:
        if i % n == 0:
            result.append(i)
    return result
out = find_multiples_list(l, 5)
out
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
find_multiples_list(l, 7)
[0, 7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98]
find_multiples_list(l, 10)
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]