11. Strings & Objects
Strings are a little different when compared to the other types we have seen (
int
,float
,bool
)Classically speaking, a string is a collection of individual characters
In fact, we can index the string to access individual characters from it
1some_string = "Hello, world!"
2print(some_string[0]) # prints out 'H'
3print(some_string[4]) # prints out 'o'
Note
In Python, and many other programming languages, the index for the beginning is actually 0
, not 1
. There are
some historical and engineering reasons for this, and there are plenty of programming languages that start at 1
too. This can feel tedious for new programmers, but it will become natural to you.
Activity
Write a single line command to print the first 4 characters of some string.
How about the 2nd to 7th characters?
Get the last three characters? Hint: what does a negative index do?
What does
print(a[0:4])
do?
11.1. For loops
We can find the length of a given string with
len(some_string)
And we know we can index individual characters from a string
Let’s write a function
vertical_print_while
that prints a string vertically (one character per line)
1def vertical_print_while(a_string: str):
2 """
3 Print out a string vertically. In other words, print out a single character on each line.
4
5 :param a_string: Some string to print out
6 :type a_string String
7 """
8 character_index = 0
9 while character_index < len(a_string):
10 print(a_string[character_index])
11 character_index += 1
Activity
Write the vertical_print_while
function yourself. Try not to just copy/paste the provided solution. Call the
function on a few different strings to see if it behaves the way you expect.
The
while
loop worked perfectly fineBut there is another type of loop called a
for
loop that may feel a little nicer to use in this scenarioThese
for
loops are great for when we have a collection of things and we want to do something for each of those things
1def vertical_print_for(a_string: str):
2 """
3 Print out a string vertically. In other words, print out a single character on each line.
4
5 :param a_string: Some string to print out
6 :type a_string String
7 """
8 for char in a_string:
9 print(char)
The
while
loop will continue to runwhile
the condition isTrue
The
for
loop will run for each thingIn this example, the
for
loop will run for each character in the stringIf we were to call
vertical_print_for("Hello")
The first time through the loop
char
would have the value"H"
The second time
char
would have the value"e"
The third time
char
would be"l"
Fourth time
char
is"l"
againThe fifth time
char
is"o"
The loop ends as there are no more characters in the string
Both the
while
andfor
loops are perfectly fine for this situationBut you may find the
for
loop has a little nicer syntax
Note
In the vertical_print_for
example, the use of the variable name char
in the for
loop is arbitrary. It is
just a variable name and is not required to be char
because the things in the string are characters. I chose
char
since it is an appropriate name for the variable. For example, the following code would work:
1for terrible_variable_name in a_string:
2 print(terrible_variable_name)
11.2. Immutability
Although we can access individual characters at a specified index
some_string[an_index]
We cannot change the value at a specified index
some_string[an_index] = "X"
If you try this, you will get
TypeError: 'str' object does not support item assignment
This is because strings are not mutable
They’re immutable
Fancy way of saying, once they exist you cannot change them
However, there is nothing stopping us from making a new string based on the old
1a_string = "Hello, world!"
2b_string = a_string[:5] + "!" + a_string[6:]
11.3. Linear Search
Searching through some collection of elements to see if something exists within it is a very common problem
This is something you have done in real life many times
However, when writing the algorithm to perform a linear search, many new programmers rush through it and make some common mistakes
Activity
Write a function character_is_in(needle: str, haystack: str) -> bool
that searches for a specific character
needle
within a string haystack
. If it exists within the string, return True
and False
otherwise.
When you finish writing your function, be sure to test it with the following assertions:
1# character_is_in tests
2assert False == character_is_in("a", "")
3assert False == character_is_in("", "hello")
4assert False == character_is_in("a", "hello")
5assert True == character_is_in("h", "hello")
6assert True == character_is_in("o", "hello")
Activity
What’s wrong with the following function? Trace through the logic on each of tests cases for character_is_in
above to help you find the issue.
1def broken_character_is_in(char, string):
2 count = 0
3 while count < len(string):
4 if string[count] == char:
5 return True
6 else:
7 return False
8 count = count + 1
11.3.1. Underlying Idea
Generalizing beyond strings, we can do a linear search on many other things
For example, a stack of exams, a lineup of people
It’s important to note that, we can confirm that a given thing exists within a collection as soon as we find it
If I am looking for \(x\) in a sequence, I can confirm its existence as soon as I see it
For example, consider looking for \(x\) in the following sequence of unknown elements
\([?, ?, ?, ?, ?, ...]\)
When starting, we do not know any of the values in the sequence until we look at them
If I look at the beginning of this sequence and see that the value is \(x\), I am done
It’s there — no need to keep looking
\([x, ?, ?, ?, ?, ...]\)
However, if I was looking for some other value, like \(y\), I cannot confirm that it is or is not there just by looking at the beginning element and finding an \(x\)
I would need to keep going
I can only confirm that something is not in the sequence until I have looked at all elements in the sequence
If I had a sequence of length \(10\), I would need to look at all \(10\) before I can guarantee that something is or is not within it
If it was length \(20\), I would need to look at all \(20\)
If it was length \(n\), I would need to look at all \(n\)
Activity
Write a function character_is_at(needle: str, haystack: str) -> int
that returns the index of the first
occurrence of the character needle
within the string haystack
. If the character does not exist within the
string, return -1
.
Test your function with the following assertions:
1# character_is_at tests
2assert -1 == character_is_at("a", "")
3assert -1 == character_is_at("", "hello")
4assert -1 == character_is_at("a", "hello")
5assert 0 == character_is_at("h", "hello")
6assert 4 == character_is_at("o", "hello")
7assert 2 == character_is_at("l", "hello")
11.4. String Trivia
'
or"
will work for the quotes needed for strings1a = "This is a string" 2b = 'this is also a string'
We can concatenate strings with
+
1a = "CSCI" + " " + "161" 2print(a) # results in "CSCI 161"
We can make a string repeat with
*
1a = "CSCI" * 3 2print(a) # results in "CSCICSCICSCI"
We can convert an
int
to astr
1print(type(1)) # <class 'int'> 2print(type(str(1))) # <class 'str'>
The string
""
is a string, but it’s empty1a = "" 2print(len(a)) # results in 0 3print(type(a)) # results in <class 'str'>
We have some special characters that we have no keys for on the keyboard, like a newline or an indent tab
'\n'
'\t'
There are many
1a = 'hello\nWorld\tFUN\\!' 2print(a) 3# hello 4# World FUN\!
- ASCII Table
Every character is a number
1wut = ord('a') # get the num of "a" 2print(wut) # results in 97 3 4wut = chr(65) # convert num to char 5print(wut) # results in "A"
11.5. f-Strings
There are a number of ways to format strings in Python, but we will focus on f-Strings due to their simplicity and popularity
1name = "John Doe"
2course_code = "CSCI 161"
3to_print = f"My name is {name} and I love {course_code}."
4print(to_print) # My name is John Doe and I love CSCI 161.
In the previous example, all the variables were of type string, but they don’t have to be
We can even format the output of a floating point number to a specified decimal place
1some_integer = 123
2some_float = 456.789
3to_print = f"The following is an integer {some_integer}, and this is a float to 2 decimal places {some_float:.2f}."
4print(to_print) # The following is an integer 123, and this is a float to 2 decimal places 456.79.
You can even specify align output nicely with f-Strings
For example, if you wanted to format some output of something like a bill and you wrote the following, it wouldn’t look too nice
1# Ugly
2print(10.95)
3print(1.10)
4print(123.45)
5
6# Output
7# 10.95
8# 1.1
9# 123.45
Notice how the decimal place does not align well
If instead we used f-Strings like this, it would look much better
1# Pretty
2print(f"{10.95:8.2f}")
3print(f"{1.10:8.2f}")
4print(f"{123.45:8.2f}")
5
6# Output
7# 10.95
8# 1.10
9# 123.45
Literal values were included in the above example, but this would also work with variables
Warning
This only scratches the surface of what you can do with f-Strings. Further, much of the same functionality can be done without f-Strings, but f-Strings are very popular and simple.
If you are wondering “how am I supposed to remember all this?”, don’t worry — you’re not supposed to. All that you really need to remember is that f-Strings are a thing and if you need to use them in the future, just do a quick search on Google.
11.6. Objects
Warning
Much of the following is going to be kept at a very high level and not quite accurate for Python. That said, the underlying ideas being presented below are important. Additionally, more details on Objects are presented later in the course.
We have seen a few types so far
Most of these are what we call primitive types
Integers
Floats
Booleans
But we have also seen Strings and how they are a little different
Strings are objects and work a little different
11.6.1. Methods
We’ve seen built in functions
print('this is a function')
We’ve written our own functions
character_is_in('a','bleh')
However, there is also something called a method that is very similar to a function, but acts on a specific instance of an object
Activity
- In Colab:
Assign a string to some variable and print it out
After running the code, type the name of the variable
Press
.
(period)Wait (or press space, or tab, or ctrl-space
You should see a menu pop up that looks like the following:
The menu that popped up contains methods that can be run on a string
Other objects that we will see later in the course will have methods associated with them too
Activity
Assign some string to a variable called
a_string
Add the line of code
a_string.upper()
and thenprint
outa_string
Try some of the other methods and see what they do
11.6.2. Method vs. Function
Why do we have to do it with a method
a_string.upper()
Instead of a function like this?
upper(a_string)
In reality, there is nothing stopping us from writing the function
upper(a_string)
But with the string, the sequence of characters that make up the string are stored in the object
The method
a_string.upper()
is about the data within the objectThe functionality that manages the data in that object will belong to that object
11.6.3. How to Remember What’s What
Don’t
Things will stick once you get enough practice