This tutorial is adapted from one developed by John DeNero and Dan Klein at UC Berkeley.
Do the following steps to get the starting point code. Replace USERNAME with your own username.
You may find the Troubleshooting section helpful if you run into problems. It contains a list of the frequent problems previous students have encountered when following this tutorial.
python3
at the Unix command prompt.
$ python3
Python 3.8.10 (default, Nov 26 2021, 20:14:08)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> exit()
>>>
) they will
be evaluated and the result wil be returned on the next line.
>>> 1 + 1
2
>>> 2 * 3
6
Boolean operators also exist in Python to manipulate the primitive True
and False
values.
>>> 1==0
False
>>> not (1==0)
True
>>> (2==2) and (2==3)
False
>>> (2==2) or (2==3)
True
+
operator is overloaded
to do string concatenation on string values.
>>> 'artificial' + "intelligence"
'artificialintelligence'
>>> 'artificial'.upper()
'ARTIFICIAL'
>>> 'HELP'.lower()
'help'
>>> len('Help')
4
' '
or double quotes " "
to surround string. This allows for easy nesting of strings.
>>> s = 'hello world'
>>> print(s)
hello world
>>> s.upper()
'HELLO WORLD'
>>> len(s.upper())
11
>>> num = 8.0
>>> num += 2.5
>>> print(num)
10.5
Exercise 1: Learn about the methods Python provides for strings. In the file ex1_strings.py show some examples of applying the string methods.
To see what methods Python provides for a datatype, use the dir
and help
commands:
>>> s = 'abc'
>>> dir(s)
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__ge__',
'__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__','__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__','__repr__', '__rmod__', '__rmul__', '__setattr__', '__str__', 'capitalize', 'center',
'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'replace', 'rfind','rindex', 'rjust', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
>>> help(s.find)
Help on built-in function find:
find(...)
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.
>> s.find('b')
1
Try out some of the string functions listed in dir
(ignore those with underscores '_' around the method name).
>>> fruits = ['apple','orange','pear','banana']
>>> fruits[0]
'apple'
We can use the +
operator to do list concatenation:
>>> otherFruits = ['kiwi','strawberry']
>>> fruits + otherFruits
>>> ['apple', 'orange', 'pear', 'banana', 'kiwi', 'strawberry']
Python also allows negative-indexing from the back of the list.
For instance, fruits[-1]
will access the last
element:
>>> fruits[-1]
'banana'
>>> fruits[-2]
'pear'
>>> fruits.pop()
'banana'
>>> fruits
['apple', 'orange', 'pear']
>>> fruits.append('grapefruit')
>>> fruits
['apple', 'orange', 'pear', 'grapefruit']
>>> fruits[-1] = 'pineapple'
>>> fruits
['apple', 'orange', 'pear', 'pineapple']
fruits[1:3]
which returns a list containing
the elements at position 1 and 2. In general fruits[start:stop]
will get the elements in start, start+1, ..., stop-1
. We can
also do fruits[start:]
which returns all elements starting from the start
index. Also fruits[:end]
will return all elements before the element at position end
:
>>> fruits[0:2]
['apple', 'orange']
>>> fruits[:3]
['apple', 'orange', 'pear']
>>> fruits[2:]
['pear', 'pineapple']
>>> len(fruits)
4
The items stored in lists can be any Python data type. So for instance
we can have lists of lists:
>>> lstOfLsts = [['a','b','c'],[1,2,3],['one','two','three']]
>>> lstOfLsts[1][2]
3
>>> lstOfLsts[0].pop()
'c'
>>> lstOfLsts
[['a', 'b'],[1, 2, 3],['one', 'two', 'three']]
dir
and
get information about them via the help
command. In the file ex2_lists.py show examples of testing lists.
>>> dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
'__delslice__', '__doc__', '__eq__', '__ge__', '__getattribute__',
'__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__',
'__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__',
'__rmul__', '__setattr__', '__setitem__', '__setslice__', '__str__',
'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse',
'sort']
>>> help(list.reverse) Help on built-in function reverse: reverse(...) L.reverse() -- reverse *IN PLACE*
>>> lst = ['a','b','c']
>>> lst.reverse()
>>> ['c','b','a']
Note: Ignore functions with underscores "_" around the names; these are private helper methods.
>>> pair = (3,5)
>>> pair[0]
3
>>> x,y = pair
>>> x
3
>>> y
5
>>> pair[1] = 6
TypeError: object does not support item assignment
The attempt to modify an immutable structure raised an exception. Exceptions indicate errors: index out of bounds errors, type errors, and so on will all report exceptions in this way.
>>> studentIds = {'knuth': 42.0, 'turing': 56.0, 'nash': 92.0 }
>>> studentIds['turing']
56.0
>>> studentIds['nash'] = 'ninety-two'
>>> studentIds
{'knuth': 42.0, 'turing': 56.0, 'nash': 'ninety-two'}
>>> del studentIds['knuth']
>>> studentIds
{'turing': 56.0, 'nash': 'ninety-two'}
>>> studentIds['knuth'] = [42.0,'forty-two']
>>> studentIds
{'knuth': [42.0, 'forty-two'], 'turing': 56.0, 'nash': 'ninety-two'}
>>> studentIds.keys()
['knuth', 'turing', 'nash']
>>> studentIds.values()
[[42.0, 'forty-two'], 56.0, 'ninety-two']
>>> studentIds.items()
[('knuth',[42.0, 'forty-two']), ('turing',56.0), ('nash','ninety-two')]
>>> len(studentIds)
3
As with nested lists, you can also create dictionaries of dictionaries.
Exercise 3: Use dir
and help
to learn about the functions you can call on dictionaries. In the file ex3_dictionaries.py show examples of testing dictionaries.
for
loop.
Exercise 4: Open the file
ex4_foreach.py
which includes the following code:
# This is what a comment looks like
# Here is a list of fruits for sale
fruits = ['apples','oranges','pears','bananas']
for fruit in fruits:
print(fruit + ' for sale')
# Here is a dictionary mapping fruit names to prices
fruitPrices = {'apples': 2.00, 'oranges': 1.50, 'pears': 1.75}
for fruit, price in fruitPrices.items():
if price < 2.00:
print('%s cost %f a pound' % (fruit, price))
else:
print(fruit + ' are too expensive!')
At the command line, use the following command to execute the program:
$ python3 ex4_foreach.py
This program should produce the following output:
apples for sale
oranges for sale
pears for sale
bananas for sale
oranges cost 1.500000 a pound
pears cost 1.750000 a pound
apples are too expensive!
if else
and for
loops) in Python, check out the official Python tutorial section on this topic.In python, list comprehension is a shorthand way of creating a new list based on the values within an existing list.
For example, suppose we had a list called nums with the values [1,6,2,5,3,4] and we wanted to create a new list with these values each multiplied by 10. One way to accomplish this would be to use a for loop as shown below:
new_nums = []
for x in nums:
new_nums.append(x*10)
However, list comprehension allows you to create this new list in a single line of code like this:
new_nums = [x*10 for x in nums]
Here are some more examples of list comprehension:
nums = [1,6,2,5,3,4] plusOneNums = [x+1 for x in nums] print(plusOneNums) oddNums = [x for x in nums if x % 2 == 1] print(oddNums) oddNumsPlusOne = [x+1 for x in nums if x % 2 ==1] print(oddNumsPlusOne)
Exercise 5: Put the above code in the file
called ex5_listcomp.py
. Add a few of your own list
comprehension examples. Then you can run it like this:
$ python3 ex5_listcomp.py
Ensure that the output it produces makes sense to you.
Exercise 6: Write a list comprehension which, from a list of strings, generates a lowercased version of each string that has length greater than five. Call your solutionex6_listcomp.py
.
For example, when given the list:
["Artificial", "Intelligence", "Is", "Fun"]
Your list comprehension should return the list:
["artificial", "intelligence", "Is", "Fun"]
To accomplish this you will need to use the following syntax for a more complex form of list comprehension that includes both an if and an else.
[f(x) if condition else g(x) for x in sequence]
This should be interpreted as follows: for every item x
in the sequence, if the condition is True, then apply the
function f to that item, otherwsie apply the
function g to that item.
NOTE: Successfully applying list comprehension within your python programs can make them more concise and easier to read.
if 0 == 1: print('We are in a world of arithmetic pain') print('Thank you for playing')will output
Thank you for playing
But if we had written the program as
if 0 == 1:
print('We are in a world of arithmetic pain')
print('Thank you for playing')
there would be no output. The moral of the story: be careful how you indent!
def
as
shown below. Notice that all of the commands indented under
the def
become part of the function definition. The
following program is in a file called fruit.py
:
fruitPrices = {'apples':2.00, 'oranges': 1.50, 'pears': 1.75}
def buyFruit(fruit, numPounds):
if fruit not in fruitPrices:
print("Sorry we don't have %s" % (fruit))
else:
cost = fruitPrices[fruit] * numPounds
print("That'll be %f please" % (cost))
def main():
buyFruit('apples',2.4)
buyFruit('coconuts',2)
main()
Then execute this program:
$ python3 fruit.py
That'll be 4.800000 please
Sorry we don't have coconuts
Exercise 7: Implement
the buyLotsOfFruit(orderList)
function in a program
called ex7_buyLotsOfFruit.py
which takes a list
of (fruit,pound)
tuples and returns the cost of your
list. If there is some fruit
in the list which does not
appear in fruitPrices
it should print an error message
and return None
, which is a special value in Python,
like null in C or C++.
Test Case: Check your code by testing that the program correctly outputs:
Cost of [('apples', 3.0), ('pears', 1.0), ('oranges', 2.0)] is 10.75
FruitShop
.
All of the methods are indented beneath the initial line that defines
the class. Each method has comments, enclosed within a triple quoted
block, describing its parameters and purpose. The first method,
called __init__
, is the constructor for the class. Notice
that all of the methods have a first parameter
named self
, which will be explained when we test this
class.
The following class definition is in a file called shop.py
.
class FruitShop(object):
def __init__(self, name, fruitPrices):
"""
name: Name of the fruit shop
fruitPrices: Dictionary with keys as fruit strings and
prices for values, such as:
{'apples':2.00, 'oranges': 1.50, 'pears': 1.75}
"""
self.fruitPrices = fruitPrices
self.name = name
print('Welcome to the %s fruit shop' % (name))
def getCostPerPound(self, fruit):
"""
fruit: Fruit string
Returns cost of fruit, assuming it is in the dictionary
or None otherwise
"""
if fruit not in self.fruitPrices:
print("Sorry we don't have %s" % (fruit))
return None
return self.fruitPrices[fruit]
def getPriceOfOrder(self, orderList):
"""
orderList: List of (fruit, numPounds) tuples
Returns cost of orderList for all available fruit
"""
totalCost = 0.0
for fruit, numPounds in orderList:
costPerPound = self.getCostPerPound(fruit)
if costPerPound != None:
totalCost += numPounds * costPerPound
return totalCost
def getName(self):
return self.name
The FruitShop
class has some data, the name of the shop
and the prices per pound of some fruit, and it provides functions, or
methods, on this data. What advantage is there to wrapping this data
in a class?
import
shop
, since shop.py
is the name of the file.
Then, we can create FruitShop
objects as follows:
import shop
shopName = 'the Berkeley Bowl'
fruitPrices = {'apples': 1.00, 'oranges': 1.50, 'pears': 1.75}
berkeleyShop = shop.FruitShop(shopName, fruitPrices)
applePrice = berkeleyShop.getCostPerPound('apples')
print(applePrice)
print('Apples cost $%.2f at %s.' % (applePrice, shopName))
otherName = 'the Stanford Mall'
otherFruitPrices = {'kiwis':6.00, 'apples': 4.50, 'peaches': 8.75}
otherFruitShop = shop.FruitShop(otherName, otherFruitPrices)
otherPrice = otherFruitShop.getCostPerPound('apples')
print(otherPrice)
print('Apples cost $%.2f at %s.' % (otherPrice, otherName))
print("My, that's expensive!")
The above code is in a file called shopTest.py
.
You can execute it like this:
$ python3 shopTest.py
Welcome to the Berkeley Bowl fruit shop
1.0
Apples cost $1.00 at the Berkeley Bowl.
Welcome to the Stanford Mall fruit shop
4.5
Apples cost $4.50 at the Stanford Mall.
My, that's expensive!
So what just happended? The import shop
statement told
Python to load all of the functions and classes
in shop.py
. The line berkeleyShop =
shop.FruitShop(shopName, fruitPrices)
constructs
an instance of the FruitShop
class defined
in shop.py, by calling the __init__
function in
that class. Note that we only passed two arguments in,
while __init__
seems to take three
arguments: (self, name, fruitPrices)
. The reason for this
is that all methods in a class have self
as the first
argument. The self
variable's value is automatically set
to the object itself; when calling a method, you only supply the
remaining arguments. The self
variable contains all the
data (name
and fruitPrices
) for the current
specific instance.
ex8_shopSmart.py
, that contains a
function shopSmart(orders,shops)
, which takes
an orderList
(like the kind passed in
to FruitShop.getPriceOfOrder
) and a list
of FruitShop
objects and returns
the FruitShop
where your order costs the least amount in
total.
Test Case: Check that, with the following variable definitions:
order1 = [('apples',1.0), ('oranges',3.0)]
order2 = [('apples',3.0)]
dir1 = {'apples': 2.0, 'oranges':1.0}
shop1 = shop.FruitShop('shop1',dir1)
dir2 = {'apples': 1.0, 'oranges': 5.0}
shop2 = shop.FruitShop('shop2',dir2)
shops = [shop1, shop2]
The following are true:
shopSmart(order1, shops).getName() == 'shop1'
and
shopSmart(order2, shops).getName() == 'shop2'
To submit your code use git to add, commit and push the files that you modified.
This tutorial has briefly touched on some major aspects of Python that will be relevant to the course. Here are some more useful tidbits:
range
to generate a sequence of integers, useful for generating traditional indexed for
loops:
for index in range(3): print lst[index]
try
and except
to catch errors.
For example, suppose you have a dictionary that is keyed on strings
with integer values. The following snippet of code will produce an
error:d = {} d['a'] = 1 d['b'] = 2 d['c'] = 3 for letter in ['a', 'b', 'c', 'd', 'e']: print letter, "is a key with value", d[letter]One option for handling this problem is to wrap the problematic code in a try-except as shown below:
for letter in ['a', 'b', 'c', 'd', 'e']: print letter, try: value = d[letter] print "is a key with value", value except: print "is NOT a key"You can also catch an error and do nothing as shown here:
for letter in ['a', 'b', 'c', 'd', 'e']: try: value = d[letter] print letter, "is a key with value", value except: passYou can read more about handling exceptions.
reload
command:
>>> reload(shop)
Solution:
When using import
, do not include the ".py" from the filename.
For example, you should say: import shop
NOT: import shop.py
Solution:
To access a member of a module, you have to type ModuleName.MemberName
, where ModuleName
is the name of the .py
file, and MemberName
is the name of the variable (or function) you are trying to access.
Solution:
Dictionary looks up are done using square brackets: [ and ]. NOT parenthesis: ( and ).
Solution:
Make sure the number of variables you are assigning in a for
loop matches the number of elements in each item of the list.
Similarly for working with tuples.
For example, if pair
is a tuple of two elements (e.g. pair =('apple', 2.0)
) then the following code would cause the "too many values to unpack error":
(a,b,c) = pair
Here is a problematic scenario involving a for
loop:
pairList = [('apples', 2.00), ('oranges', 1.50), ('pears', 1.75)] for fruit, price, color in pairList: print '%s fruit costs %f and is the color %s' % (fruit, price, color)
Solution:
Finding length of lists is done using len(NameOfList)
.
Solution:
reload(YourModule)
to guarantee your changes are being reflected.
reload
works similar to import
.