lower, etc. to transform a string, e.g. trimming whitespace
We 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(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 function will return a list of all the methods available for an object, say a
>>> 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.
>>> 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
In general, Python evaluates expressions from left to right while observing
PEMDAS. Remember that a set of parentheses are themselves a (single)
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
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
is short for Boolean. Booleans are a type that can only take on two values
False. Booleans and Boolean logic are a key programming tool,
particularly for decision-making, that we will start learning about next week.