upper
, lower
, etc. to transform a string, e.g.
trimming whitespaceWe used several functions, like len
, that take a string as a parameter. And
written some as well. That is we (really the Python development team) have
defined a function and then invoked it with different arguments. These can be
different values, or in the case of the len
function, even parameters of
different types. For example len
can be used with other sequences, e.g.
>>> len(range(5))
5
An alternate approach is to invoke different functions on a specific value. Specifically we invoke a method on an object. A method then is a function specific to one type of object, i.e. specific to strings or integers.
Methods are invoked or called with the object.method
syntax. For example:
>>> s = "Hi CS150"
>>> s.lower()
'hi cs150'
>>> s.upper()
'HI CS150'
This approach to organizing our code is called “object-oriented programming” (OOP), because the data and the functions are contained within/associated with objects. And for the purposes of this class all objects of a specific type, e.g. all string objects, have the same set of methods.
Methods are very similar to the functions we have been working with: they can
accept additional parameters (in addition to the object on which they were
invoked, also termed the “receiver”) and you can obtain their docstrings with
help
, e.g.
>>> help(s.lower)
>>> help(str.lower)
But notice that we need to specify the receiver object (value) itself, or the type (class) of the receiver.
We will learn some more about OOP later in the semester (and you will learn a lot more in CSCI201), for now we want to get started using methods, particularly string methods.
So how can we learn more about the methods for an object?
dir
functionhelp
functionThe dir
function will return a list of all the methods available for an object, say a
string.
>>> dir(s)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
And because it is good practice, many of the methods have descriptive names.
e.g. find
>>> help(s.find)
Help on built-in function find:
find(...) method of builtins.str instance
S.find(sub[, start[, end]]) -> int
Return the lowest index in S where substring sub is found,
such that sub is contained within S[start:end]. Optional
arguments start and end are interpreted as in slice notation.
Return -1 on failure.
>>> ALPHABET = "abcdefghijklmnopqrstuvwxyz"
>>> ALPHABET.find("a")
0
>>> ALPHABET.find("z")
25
How can we apply a sequence of method calls? Recall that we can use the return value from one function call as the argument to another, e.g.
>>> from random import randint
>>> len(range(randint(1, 5)))
5
The equivalent pattern for method calls would be the following. You can hopefully see why this is often called “chaining”…
>>> s.lower().capitalize()
'Hi cs150'
What about the receiver? The receiver can be any expression, it is not required to a variable or literal. For example:
>>> ("gI".replace("g","h") + " CS" + str(300//2)).swapcase()
'Hi cs150'
Here we are invoking the swapcase
method on the expression inside the
parentheses. The expression inside the parentheses is evaluated first to
produce the string "hI CS150"
, and then the swapcase
method is invoked on
that string to produce the final result. A good strategy for evaluating these
types of expressions is to work step-by-step keeping in mind the order in
which Python evaluates
expressions.
In general, Python evaluates expressions from left to right while observing
PEMDAS. Remember that a set of parentheses are themselves a (single)
expression.
PI Questions (string methods, part 1)1
>>> s = "Bruce"
>>> t = s.lower()
>>> t
'bruce'
>>> s
'Bruce'
Strings in Python are immutable, that is they can’t be changed. The string methods that look like they are changing the string are actually creating a new string object. Check out the Python Tutor memory model picture for the example above.
We can see the same immutability property in the examples below (the Python Tutor memory module picture):
>>> s = "test"
>>> s.upper()
'TEST'
>>> s
'test'
>>> a = "hi"
>>> b = a
>>> a = "bye"
>>> b
'hi'
PI Questions (string methods, part 2)
Earlier we saw that strings have a method startswith
. We would guess that
method will indicate if the string starts with the supplied parameter:
>>> s = "hello"
>>> s.startswith('h')
True
>>> s.startswith('b')
False
What are True
and False
. They are not strings because they’re not enclosed
in quotes, nor are they integers or floating points numbers. They must be
values of a new type we haven’t yet encountered. Indeed they are bool
s, which
is short for Boolean. Booleans are a type that can only take on two values
True
and False
. Booleans and Boolean logic are a key programming tool,
particularly for decision-making, that we will start learning about next week.