CS193Q - Day 2

See Python Guide for reference Python Guide

Today: more string functions, foreach loop, lists, for/i/range loops, Doctests in PyCharm FTW

Today: Install PythonCharm

Install PyCharm "community edition" (free) on your computer. https://www.jetbrains.com/pycharm/download/ - use it later today. You could use a different Python IDE if you prefer. I want to use PyCharm to show off how to use Doctests as part of a productive workflow.

More String functions

Last time - we did the first half of these, here's the full list

Python Guide: Python Strings

See String chapter in the guide

>>> s
'Python'
>>> 
>>> 'th' in s     # "in" to check
True
>>> 'x' in s
False
>>> 'x' not in s  # "not in" variant
True
>>> 
>>> s.find('y')
1
>>> 
>>> s.find('yt')
1
>>> 
>>> 'yt' in s
True
>>> 
>>> s.find('y', 0)
1
>>> s.find('y', 3)
-1
>>> 
>>> 
>>> s.startswith('Py')
True
>>> 
>>> 
>>> s.endswith('Py')
False
>>> 
>>> 
>>> s.lower()
'python'
>>> 
>>> s
'Python'
>>> 
>>> 
>>> s = 'Python!'
>>> 
>>> s.lower()
'python!'
>>> 
>>> s.upper()
'PYTHON!'
>>> 
>>> 'x'.isupper()
False
>>> 
>>> 'x'.islower()
True
>>> 
>>> 
>>> '9'.isdigit()
True
>>> 
>>> 
>>> 'x'.isalpha()
True
>>> 
>>> '!'.isalpha()
False
>>> 
>>> '   key data here    \n'.strip()
'key data here'
>>> 
>>> 
>>> 'this is it'.replace('is', 'is not')
'this not is not it'
>>> 
>>> 
>>> 'this is it'.replace('is', 'xxx')
'thxxx xxx it'
>>> 
>>> # old way to str / int: 
>>> 'score:' + str(45)
'score:45'
>>>
>>> # new - format strings:
>>> name = 'Alice'
>>> 
>>> f'this is {name}'
'this is Alice'
>>> 
>>> x = 12
>>> f'value: {x}'
'value: 12'
>>> 
>>> f'value: {x * 10}'
'value: 120'
>>>
>>> x = 2/3
>>> f'value: {x}'
'value: 0.6666666666666666'
>>> f'value: {x:.4}'
'value: 0.6667'
>>> 

Work With Immutable

The pattern for working with immutable strings:

x = change(x)

>>> s = 'HELLO there'
>>> s.lower()
'hello there'
>>> s
'HELLO there'
>>> s = s.lower()
>>> s
'hello there'

String Foreach Loop

We'll see a couple loop forms today. The simple for loop takes a var, and sets it to point to each element, one per iteration. The easiest way to look at each element. With strings, each element is a single char.

Syntax: for VAR in STR:

On each iteration of loop, var points to next char, 'P', 'y', ...

Here just typing it in the interpreter for a demo. Could use any var name, does not need to be "ch"

>>> s = 'Python'
>>> for ch in s:
...     print(ch)
... 
P
y
t
h
o
n

Compute something looping over string...

>>> result = ''
>>> for ch in s:
...     result += ch + ch
... 
>>> # what is result now?
>>> 
>>>
>>>

Answer: 'PPyytthhoonn'


Python List

Python Guide: Python Lists

>>> lst = []
>>> len(lst)
0
>>> 
>>> lst.append('abc')
>>> 
>>> lst
['abc']
>>> 
>>> lst.append('xyz')
>>> 
>>> lst.append('cat')
>>> 
>>> lst
['abc', 'xyz', 'cat']
>>> 
>>> len(lst)
3
>>> 
>>> 'cat' in lst
True
>>> 
>>> lst
['abc', 'xyz', 'cat']
>>> 
>>> 
>>> lst2 = ['dot', 'bird']
>>> 
>>> lst.append(lst2)
>>> lst
['abc', 'xyz', 'cat', ['dot', 'bird']]
>>> 
>>> 
>>> lst = ['abc', 'xyz', 'cat']
>>> 
>>> # + between lists - like string
>>> lst + ['a', 'b']
['abc', 'xyz', 'cat', 'a', 'b']
>>>
>>> lst
['abc', 'xyz', 'cat']
>>> 
>>> 
>>>
>>> lst2
['dot', 'bird']
>>> 
>>> lst + lst2
['abc', 'xyz', 'cat', 'dot', 'bird']
>>> 
>>> 
>>> lst
['abc', 'xyz', 'cat']
>>> 
>>> lst.extend(lst2)
>>> 
>>> lst
['abc', 'xyz', 'cat', 'dot', 'bird']
>>> 
>>> 

Python No Copy

The = never makes a copy, just shallow pointers. There is a .copy() function - very rare to use.

In C/C++ you make copies all the time, often I think because there is no GC. Need copies so they can be deleted ad separate times. It's natural for a Python program works ok with just a bunch of pointers and just 1 copy of each structure. So the .copy() function shown below is rarely used.

>>> a = [1, 2, 3]
>>> b = a
>>> 
>>> b.append(13)
>>> b
[1, 2, 3, 13]
>>> a
[1, 2, 3, 13]
>>> 
>>> # can make explicit copy - rare
>>> c = a.copy()
>>> c.append(42)
>>> c
[1, 2, 3, 13, 42]
>>> a
[1, 2, 3, 13]

Foreach Loop 1

for s in ['a', 'b', 'c', 'd']:
   print(x)

alt: loop over strings in list

Range Functions

range(6)  -> [0, 1, 2, 3, 4, 5]  # UBNI
range(2)  -> [0, 1]
range(1)  -> [0]
range(0)  -> []                

range(n) -> [0, 1, 2 .... n-1]

In interpreter, wrap in list() function, so it prints out right: >>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] list(reversed(range(10))) [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] >>> list(range(1, 20, 2)) [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

Foreach Loop 2

>>> lst = ['a', 'b', 'c', 'd']
>>> for i in range(len(lst)):
...   print(i, lst[i])
... 
0 a
1 b
2 c
3 d
>>>

C Translation

# Common C loop
C: for (int i = 0; i < n; i++)

# range(n) is just a canned version of above
Python: for i in range(n):

Doctests In PyCharm

A Python IDE has many language related features which really can save you time.

Today: Run PyCharm. Use its "Open..." command to open either (a) the whole code2 folder, or (b) the exercise2.py file within that folder. Either will work, but opening the folder gives you access to all the .py files in that folder, which is typically what you want.

At the bottom right of the window, it should say "Python 3.12" (or whatever your installed Python is). If no, click there to select your Python. You may need to click Add New Interpreter > Add Local Interpreter > System Interpreter > (select the one you want to use). The differences between different 3.11+ versions are small, but you might as well run something recent.

Doctest Demo

If Python is installed in PyCharm, Doctests will appear in a different color. Right-click the Doctest in a function to run just that test. See the results below. Super handy!

Right click in a space between functions ... run all the Doctests in the file.

Doctest Productivity Workflow

Working on some helper function. Write a few Doctests next to the code itself. Can write these before writing any code. Now work on the code .. check the tests as you go. When the function works, it's tested as well, and you can move on to the next thing with confidence.

Lesson of modern coding: tests do not need to be exotic or difficult to catch most bugs. Have 1 or 2 "basic" tests that are obvious cases. then add a couple "edge" cases (e.g. empty string) at the boundaries. Small, obvious tests catch many, many bugs.


Exercise: list-ex.py

homework-printly.html

See the Command Line guide chapter for a working example