See Python Guide for reference Python Guide
Today: more string functions, foreach loop, lists, for/i/range loops, Doctests in PyCharm FTW
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.
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' >>>
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'
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 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'] >>> >>>
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]
for s in ['a', 'b', 'c', 'd']: print(x)
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]
>>> lst = ['a', 'b', 'c', 'd'] >>> for i in range(len(lst)): ... print(i, lst[i]) ... 0 a 1 b 2 c 3 d >>>
# 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):
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.
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.
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.
See the Command Line guide chapter for a working example