lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · web viewcsc 401 –...

23
CSC 401 – LECTURE #8 Yosef Mendelsohn The random module Let's begin by reviewing the module random. Practice problem: Implement a function guess() that takes an integer n as a parameter and implements a simple, interactive guessing game. The function should start by choosing a random integer number in the range from 1 up to and including n. The function should then repeatedly ask the user to enter to guess the chosen number. When the user guesses correctly, the function should print a ‘You got it’ message and terminate. Each time the user guesses incorrectly, the function should indicate whether the guess was too high or too low. If the user types something other than an integer, the function should recover gracefully. >>> guess(100) Enter your guess: fifty That was not a valid number. Enter your guess: 50 Too high Enter your guess: 25 Too low Enter your guess: 38 Too high Enter your guess: 31 Too high Enter your guess: 28.5 That was not a valid number. Enter your guess: 28

Upload: phamkhanh

Post on 25-Aug-2018

213 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

CSC 401 – LECTURE #8Yosef Mendelsohn

The random moduleLet's begin by reviewing the module random.

Practice problem: Implement a function guess() that takes an integer n as a parameter and implements a simple, interactive guessing game.

The function should start by choosing a random integer number in the range from 1 up to and including n.

The function should then repeatedly ask the user to enter to guess the chosen number. When the user guesses correctly, the function should print a ‘You got it’ message and terminate. Each time the user guesses incorrectly, the function should indicate whether the guess was too high or too low.

If the user types something other than an integer, the function should recover gracefully.

>>> guess(100)Enter your guess: fiftyThat was not a valid number.Enter your guess: 50Too highEnter your guess: 25Too lowEnter your guess: 38Too highEnter your guess: 31Too highEnter your guess: 28.5That was not a valid number.Enter your guess: 28Too highEnter your guess: 26You got it!

See the solution in this week's file.

Review of loops and collectionsTo review loops and two-dimensional lists, we will do a practice problem.

Page 2: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

Implement a function csv_to_list() that transforms a .csv spreadsheet into a Python two-dimensional list. Your function will take as input the name of the .csv file and return the corresponding two-dimensional list.

Here is what the cities.csv file looks like when opened up in a text editor:

The following is an example of how the function would be used:

>>> csv_to_list(‘cities.csv’)[[‘Paris’, ‘Sao Paulo’, ‘Tokyo’, ‘Kinshasa’], [‘London’, ‘Mexico City’, ‘Seoul’, ‘Lagos’], [‘Moscow’, ‘New York’, ‘Mumbai’, ‘Cairo’]]

Here is the same function invoked on the file data.csv

>>> csv_to_list(‘data.csv’)[[‘3’, ‘5’, ‘6’, ‘4’], [‘8’, ‘5’, ‘2’, ‘3’], [‘2’, ‘8’, ‘9’, ‘1’]]

The solution is found in this week's code solutions.

Python objectsAnything that contains a value in Python is an "object".

A Python object has three properties:1. An identity (don't confuse with 'identifier')2. A type3. A value

The object’s identity is a unique integer ID assigned to the object.

This ID is the object’s memory address. This identity is accessible using the built-in function: id().

>>> a = 7>>> id(a)505493992

>>> lst = [3, 4, 5]>>> id(lst)31078800

2

Page 3: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

>>> id(lst[0])505493928

>>> id(lst[1])505493944

>>> id(lst[2])505493960

As you know, every value in Python has a data type. The type of an object is accessible using the built-in function: type()

>>> type(lst)<class 'list'>

>>> type(a)<class 'int'>

>>> type('hello')<class 'str'>

>>> type(None)<class 'NoneType'>

The value is the data that the object represents.

>>> a7

>>> lst[3, 4, 5]

ConstructorsWe are about to enter the world of "object oriented programming". As we get ready to create our own data types (called "classes"), it is useful to discuss / review an alternative way to create new instances of the various data types with which we are already familiar such as lists, integers, sets, and dictionaries.

We are all familiar with creating a list by using the square brackets:>>> my_lst = []

However, we can also generate a new list by invoking a function called: list()The fact that the name of the function is identical to the name of the data type is not a concidence. We will discuss this further, shortly.

So we can rewrite the earlier line of code as:>>> my_lst = list()

This function is an example of a special group of functions known as constructors.

3

Page 4: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

There are similar constructor functions for: Integers: int()

num1 = int() #new int object with a default value #this default value depends on the type# for integers, the default value is 0

num2 = int(3) #new int object with a value of 3

Strings: str()o name = str('Jim')

Sets: set()o years = set( (1971,1972,1973) )

Dictionaries: dict() etc

As you can see, constructor functions (typically just called 'constructors') can typically be passed certain parameters. These parameters are usually used to assign default values to the new object that is being created.

4

Page 5: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

Aside: Variable vs ObjectWe are very familiar with the idea of a variable. In many programming languages, there is a clear distinction between 'variables' and their more complex cousins, 'objects'. However, in Python, everything – even the most "simple" variable, is still considered to be an object. Therefore, you will frequently hear the terms used interchangably. Moving forward, though, we should start using the term "object" more frequently, since it is a more accurate description of the item we are working with.

When a constructor is invoked with zero parameters, the function assigns a default value to its variable. For example the constructor for the integer constructor, int(), assigns a 0.

>>> x1 = int(43) >>> x143

>>> x2 = int() #default constructor>>> x20

>>> lst1 = list([1, 2, 3])

>>> lst1[1, 2, 3]

>>> lst2 = list()

>>> lst2[]

Note: A constructor that takes zero parameters is given a special name, the"default constructor"

For example, if we were to create a new string as follows:s = str()

then we can say that we invoked the default constructor of the string class.

Terminology

Function vs MethodNote: A function and a method are essentially the same thing. However, we typically use the term method when we are referring to a method associated with a particular class.

For example: print() is a function.

5

Page 6: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

However, print() compare the function with another familiar function: upper(). Note that is upper()is meant to work with a string:

s = 'Hello, how are you's.upper() #returns 's' in upper case

Therefore, upper() should probably be called a ‘method’ as opposed to a ‘function’.

Compare with the function len() which can be invoked on its own:len([3,4,5])

This means that len() is a function.

Imagine you have the following objects: name = 'Bob Smith'nums = [2,3,4]

len(lst) len() is a functionnums.append(5) append() is a method of the class 'list'nums.remove(2) remove() is a method of the class 'list'print(nums) print() is a functionfin = open('example.txt') open() is a functions.isupper() isupper() is a method of the class 'string'

Every class is essentially a list of:1. class attributes 2. class functions (which we call "methods")

AttributesEach object of a type (i.e. each instance of a type) inherits the class attributes, that is, the variables and methods of that class. At the moment you don't understand what we mean by 'variables of a class', however, we will cover this shortly. However, you will be able to understand what we mean by 'methods of a class' as shown below.

Suppose you have the following statement:

s = 'hello, how are you?'

Because s is an object of type string, it inherits all attributes defined in in the string class,

6

Page 7: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

Methods defined in class str include: upper, format, find, replace, and many others. You are already fairly familiar with some of these.

In other words, because 's' is an object of the string class (str), it inherits all of the methods from that class and can therefore do things like:

s.upper()s.format(…)s.find(…)etc

Let's look at an object of type list: s = [3,4,5] #s is now an object of class list

Because s is now an object of type 'list', s now inherits all attributes available in the class list.

So the object ‘s’ can now invoke list methods:s.append(-4)s.pop()s.clear()etc

As you know, the attributes for any class type can be seen using the help function. For example, let’s view the help for the ‘int’ class:

>>> help(int)Help on class int in module builtins:

class int(object) | int(x[, base]) -> integer | | Convert a string or number to an integer, if possible. A floating | point argument will be truncated towards zero (this does not include a | string representation of a floating point number!) When converting a | string, use the optional base. It is an error to supply a base when | converting a non-string. | | Methods defined here: | | __abs__(...) | x.__abs__() <==> abs(x) | | __add__(...) | x.__add__(y) <==> x+y | | __and__(...) | x.__and__(y) <==> x&y

Etc.

7

Page 8: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

OperatorsIn learning about classes and object-oriented programming, we also need to reopen our discussion of operators (e.g. the '+' operator).

There are some subtleties that we didn’t consider before but that will be important – especially so when we start writing our own classes.

Methods with names such as __<name>__ (that is, two underscores, an identifier, and two more underscores) are special hooks that are called automatically when Python evaluates certain operators. This may not make a lot of sense just yet, but keep reading….

These “double underscore” methods are pretty famous in Python. They even have their own nickname: “dunder methods”. They have another nickname as well: “magic methods”.

If you recall, I once told you that some operators such as '+' are in fact functions. For example, the operator '+' is evaluated by Python behind the scenes by invoking a dunder method called: __add__()

If an object inherits an __add__ method (that is, if this method exists inside the class), that method will be automatically invoked when the invoking object appears on the left side of a + expression.

Okay, so that's pretty confusing. It will help to look at an example:

Example:x = 3 #x is an object of type ‘int’y = x+5

For the second line, , behind the scenes, Python evaluates the x+5 statement as:x.__add__(5)

So behind the scenes, y = x+5

is invisibly converted by Python into:y = x.__add__(5)

Restated: The moment an object of type int appears, and is followed by a '+' symbol, Python will search the 'int' class for a method called __add__ () and will invoke it.

Every single object of type ‘int’ that we create, because of the fact that it is an 'int' gets to use the __add__()method.

8

Page 9: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

In object-oriented (OO) parlance, we say that every object of type int inherits the __add__() method.

See below for some examples:

>>> x = 3>>> y = 4

>>> x + y #Python will search the class ‘int’ #for a method called __add__#It will invoke the method as: x.__add__(y) 7

#In fact, let's try invoking it that way directly:>>> x.__add__(y) 7#as you can see, does the same thing

If you type help(int), you will see among the list of methods the following: __add__(self, value) Return self+value.

You will also see methods for other familiar operators including: __sub__() subtraction e.g. n1__sub__(n2) __mul__() multiply e.g. n1__mul__(n2) __pow__() ** (ie exponent) e.g. n1__pow__(n2) etc

Let's try another one. In this example, suppose that 'x' is an object of ype 'int'. In the following method, we are asking Python to convert the integer value of x (which is 3) to a string.

>>> str(x)'3'

How did it do this? Answer: It involved one of these '__' (‘dunder’ or ‘magic’) methods. In this case, Python will search the 'int' class for a method called __str__ and will automatically invoke it.

In fact, if you typed: x.__str__() you'd get the same result:

>>> x.__str__()'3'

More examples:

9

Page 10: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

>>> lst = list([2, 3, 4, 5, 6])

>>> len(lst) #will search class 'list for __len__ 5

>>> lst.__len__() #this will give the same result5

>>> lst.__add__([4,5])[2, 3, 4, 5, 6, 4, 5]

>>> lst[2, 3, 4, 5, 6]

Exercises:1. Define three integers and use the __x__ notation to do absolute value,

and the < (less than) operations. The magic/dunder methods corresponding to these are called: abs, and lt respectively. Note: If you want to look at the help for mathematical operators

functions in the API, most are defined in the module 'operator'.2. Define three lists and use the __x__ notation for the operators contains,

len, and getitem.

Calling methodsAs you are well aware, when invoking methods of some object, it is common to write:

obj.method(p1, p2, …)Where: obj is the object method is the method p1, p2, … etc. are the parameters.

For example: s = "hello"s.upper()

Or perhaps:s.index('e')

Or suppose we have a list as follows:>>> lst = []

we invoke methods on that object like so:

>>> lst.append(4)>>> lst.append(-3)

10

Page 11: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

>>> lst[4, -3]

In other words, we are quite familiar with the syntax: lst.append(4)

However….

It is very important that we understand that a method call in this (familiar) form:

obj.method(param1, param2, etc)

is transformed behind the scenes into the following form:

className.method(obj, param1, param2, etc …)

where className is the class associated with the object.

For example, to append the number 4 to a list called lstNumbers:

We will almost always write: lstNumbers.append(4)

However behind the scenes, this command is always transformed into:

list.append(lstNumbers, 4)

In this example then, 'list' is the class name 'append' is the method name And very important to note is that the object on which we wanted

to invoke our method 'lstNumbers' is simply passed as the first parameter to the 'append' function.

>>> list.append(lstNumbers, -3)

>>> lst[4, -3]>>>

This information may not seem important right now, but it will become quite relevant when we start creating our own classes.

Creating a programmer-defined classClasses provide a way for the programmer (e.g. you!) to define entirely new data types.

11

Page 12: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

Consider our first example, also found in the file first_class.py:

class MyClass(object): '''a user-defined wrapper class'''

version = 1.0

def setTo(self, value): ‘sets the instance variable data to value’

self.data = value # ‘data’ is an "instance" variable

def get(self): ‘returns the value of the instance variable data’ return self.data

There are a lot of things to explain here, but let’s first start by using this new type.

The name of our new data type is 'MyClass'.

We can create an object of type MyClass using a constructor:

>>> x = MyClass()

We will talk in detail about constructors a little down the road. For now we will simply note that a constructor is a special method that we use to create a new instance (i.e. to create a new object) of our class.

Recall that the function type() tells us the data type of an object.

We can check that x refers to an object of type MyClass:

>>> type(x)<class '__main__.MyClass'>

Once we have a MyClass object, we can invoke its class methods:

>>> x.setTo(9)>>> x.get()9

We can change the value that this object holds:

>>> x.setTo('hello')>>> x.get()'hello'

12

Page 13: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

Finally, we can use the help() function just like we would on a built-in type:

>>> help(MyClass)Help on class MyClass in module __main__:

class MyClass(builtins.object) | Methods defined here: | | get(self) | returns the value of the instance variable data[…]| Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined)| Data and other attributes defined here: | | version = 1.0

Important:Docstrings: Note that because we wrote a docstring for every class function, the help() tool uses it as a part of the documentation.

Also note that we defined a docstring for the class itself.

Creating a classA user-defined type is created using the class keyword:

class <Class Name> (<Super Class>):

1. Start with the keyword ‘class’2. Following the class keyword is <Class Name>, the name of the class.3. In parentheses and following the class name is a "superclass". The superclass is

the class that <Class Name> (i.e. the class you are creating) "inherits" attributes from.

In Python 3.0 and later it is recommended that a user-defined class always inherit from a pre-existing class.

If no existing class to inherit from is appropriate, then we can have our class inherit from Python's built-in class which is called: object.

The class object has no attributes at all and thus any class inheriting from it will inherit 0 class attributes.

13

Page 14: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

>>> type(object)<class 'type'>

>>> help(object)Help on class object in module builtins:

class object | The most base type

A class statement is not very different from a def statement.

Recall that the def statement defines a new function and gives the function a name.

Similarly, the class statement defines a new data type and gives that new data type a name.

The assignments and function definitions inside a class statement define the class attributes. Recall that by 'attributes' we are referring to any functions (methods) and variables that belong to the class.

In the class MyClass, the following attributes are defined: one "instance" variable: data one "class" variable: version two methods: setTo() and get()

version = 1.0 # version is a class variable

def setTo(self, value): # setTo is a class method 'sets the instance variable data to value' self.data = value # data is an instance variable

def get(self): # get is a class method 'returns the value of the instance variable data' return self.data # data is an instance variable

Class attributes consist of class variables that determine the state of the class (i.e. the values of the variable(s) of that class), as well as class functions that determine the behavior of the class, i.e. the functions that the class supports. An instance of a class simply means a variable (or more accurately, an object) of that class.

For example, if you created an object of type MyNewClass() called 'x', then 'x' is said to be an "instance" of class MyNewClass.

All instances of a class are objects that inherit the state and behavior of that class.

14

Page 15: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

Example: Let's create, or in object-oriented termnology, " instantiate" (i.e. create an instance of) two objects:

>>> x = MyClass()>>> y = MyClass()

We have just instantiated two objects of type MyClass.

Both of these objects inherit the version class variables:

>>> x.version1.0>>> y.version1.0

"Class variables" are special variables and will be discussed later.

Both objects also inherit the two class methods:

>>> x.setTo('hello')

>>> y.setTo(3)

>>> x.get()'hello'

>>> y.get()3

The method setTo takes as a parameter one argument (value) and assigns it to the variable data.

But if you look at the definition of the class, that doesn’t seem right. The function setTo is defined to take two arguments (self and value), not just one!

We will explain the role of the first argument in a moment.

Note for now that the variable data has a ‘self.’ prefix.

The variable data is an "instance" variable. By contrast, it is NOT a "class" variable.

NOR is 'data' a local variable (i.e. it is not a varialbe that is local to the method setTo).

The variable data is an instance variable whose scope and existence is tied to the instance.

That is, every object (or 'instance') of type MyClass will have its own copy of the variable data.

15

Page 16: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

In the above example, x will have its own copy of the variable data. The object y will also have its own copy of the variable data. These separate copies are tied to the object. That is, they live in their own namespace and can not conflict with each other (unless you do something weird!)

Namespaces and classesWhen Python works with classes, behind the scenes, it is working with namespaces.

Every instance creates its own namespace. We can see this by accessing the data variable directly, by specifying the name space.

>>> y.data3

>>> x.data'hello'

When it comes to methods, Python automatically maps the invocation of a method by an instance of a class to a call to a function defined in the class namespace on the instance argument.

This will be on the exam.

Okay, of course it won't. ….

Or will it???

Alright, that last sentence is certainly a brutal mouthful of jargon and terminology. (And no, it won't be on your exam.)

So let's try and break it down.

Suppose we have an instance of a class, let's call it 'x': x = MyClass()

Whene we invoke a method via that instance: x.setTo(3)

The Python interpreter then always translates that statement to:MyClass.setTo(x,3)

Here is a generalization of how it works:

16

Page 17: Lecture 1 - condor.depaul.educondor.depaul.edu/ymendels/401/l9.docx  · Web viewCSC 401 – Lecture #8Yosef Mendelsohn. The random module. Let's begin by reviewing the module . random

When we invoke a method like so:

instanceName.methodName(arg1, arg2, …)

this method call is always translated by the Python interpreter into:

className.methodName(instanceName, arg1, arg2, …)

Example:word = "hello"word.upper() #would return 'HELLO'

Is translated by Python into:str.upper(word) #would return 'HELLO'

Another example:If you instantiate an object of type MyClass like so:

y = MyClass()

and you invoke:y.setTo(-14)

The Python interpreter will translate the above line to:MyClass.setTo(y, -14)

This explains the self variable that we keep seeing in the class definition.

The self argument that we refer to inside the methods of our class refers to the instance that invoked the method.

def setTo(self, value): self.data = value

def get(self): return self.data

The self.xxxx() prefix in front of instance methods refers to the instance namespace. For example, the 'x' in

x.get()refers to the 'x' namespace.

Exercise: Add a method to the class MyClass called double(). The method will double the value of the instance variable data.

See first_class_exercise.py for the solutions.

17