Lecture 4

Objectives for today

Randomness

The randint function in the random module returns a random integer from a given range:

from random import randint
>>> help(randint)
Help on method randint in module random:

randint(a, b) method of random.Random instance
    Return random integer in range [a, b], including both end points.

So if we wanted to choose a random angle to turn, specified in degrees, say while making a drawing we would do what?

randint(0, 359)

Why not 360? Recall randint is inclusive and 0 is the same as 360. We would slightly oversample not making any turn at all.

Additional optional notes on randomness

Turtle Enhancements

We saw that we can control the direction and angle of the drawing pen. What else can we control to enhance our square? Let’s check out the docs. Here we change the color of the line to be red and set the color of the interior of our square to be yellow. The key for the “fill” is invoking begin_fill before you draw the shape and then end_fill after you draw the shape.

pencolor("red")
fillcolor("yellow")
begin_fill()

draw_square_with_loop(100)

end_fill()

Strings

In previous class meetings we discussed the notion of types, and specifically the str string type. Since then we have been using strings primarily as literals (e.g., “Good morning”)

To indicate a string we surround the characters with single or double quotes. Why either or? We can use one when the other is a character within the string, e.g.,

>>> "a single quote isn't a problem"
"a single quote isn't a problem"
>>> 'neither are "quotes"'
'neither are "quotes"'

Escape Sequences

How do we get double quotes into a double quoted string? With backslash escaping.

>>> "quotes in \"quotes\""
'quotes in "quotes"'
>>> "backslashes with \\"
'backslashes with \\'
>>> print("backslashes with \\")
backslashes with \

That is one example of escape sequences. An even more common escape sequence is \n which inserts a newline character into the string (advances to new line, at the beginning of the line). For example:

>>> print("A new\nline")
A new
line

String Operators

Recall that we introduced using + for concatenation, e.g.,

>>> "hello" + " world"
'hello world'

and the multiplication operator * for duplication, e.g.,

>>> "hello" * 3
'hellohellohello'

In the context of strings, we would term + and * “overloaded” operators. That is we have overloaded the typical meaning, addition, with functionality relevant to strings.

Recall that + isn’t overloaded for concatenating integers and other “not strings”. We needed to explicitly convert integers to strings.

>>> "hello" + 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly
>>> "hello" + str(5)

How about the other direction – converting strings to integers and floats? We can use the int (and float, etc.) functions to do so.

>>> 5 + "hello"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> 5 + int("hello")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'hello'
>>> 5 + int("5")
10

Peer instruction questions (String Operators) [1] (Section A, Section B)

Strings as a Sequence

We think of a string as a single object, but a string is also a sequence of characters that can be manipulated as an ordered collection. I hope you can already sense that like for loops, sequences are a key CS (semantic) concept.

The Python operator for accessing specific elements in a sequence is [], with indices beginning at 0, i.e., an index of zero references the first element in the sequence (termed “zero-indexed”):

>>> s = "here is my string"
>>> s[0]
'h'
>>> s[5]
'i'
>>> s[10]
' '

If you try s[100] you get the error string index out of range, as we can’t access beyond the end of the sequence.

Strings as sequences and for loops

The combination of sequences and for loops is very powerful.

>>> s = "hello"
>>> for i in range(5):
...     print(s[i])
... 
h
e
l
l
o

It is “non-portable” to directly specify the length of the string in the for loop. What if we wanted to iterate through a different string? We would call the number “5” in this context a “magic number” and “magic numbers” are to be avoided. There is a len function that will return the length of the string, which we can use instead.

>>> s = "hello"
>>> for i in range(len(s)):
...     print(s[i])
... 
h
e
l
l
o

Can we put this all together to reverse a string using a for loop and indexing?

def reverse(s):
	"""
	reverses the contents of the input string s
	e.g,, if s is "hello", returns "olleh"
	"""
	r = ""
	for i in range(len(s)):
	    r = r + s[-(i+1)]
	return r

We have been using the range function to generate a sequence of indices. But a string itself is a sequence, and therefore we can use a for loop to iterate through its characters:

>>> for c in "hello":
...     print(c)
... 
h
e
l
l
o

Here, the loop variable c takes on the values ‘h’, ‘e’, ‘l’, ‘l’, ‘o’ in order. So for loops are a very powerful tool; we can actually iterate through any sequence, such as a string as above, not just through a range.

Here is an improved version of the reverse string function:

def reverse(s):
	"""
	reverses the contents of the input string s
	e.g,, if s is "hello", returns "olleh"
	"""
	r = ""
	for c in s:
	    r = c + r
	return r

Peer instruction questions (String Iteration) [1] (Section A, Section B)

Summary

  1. Strings
  2. Sequences
  3. for loops and sequences

For next time, finish Prelab 2, work on Lab 2, and study for the quiz by working on the practice quiz and the class exercises.