450 likes | 575 Views
Making Classes and objects. we’re now creating classes of objects. a class defines basic characteristics and functions that apply to all objects of that class Think of a class as a set of functions and variables that belong together to define a particular thing.
E N D
Making Classes and objects • we’re now creating classes of objects. • a class • defines basic characteristics and functions that apply to all objects of that class • Think of a class as a set of functions and variables that belong together to define a particular thing. • E.g., Savings Account classes would have: • A balance #variable, or attribute • An owner’s name #variable, or attribute • The ability to add money to the account #function, or method • The ability to withdraw money from the account #function, or method • An individual’s Savings Account might have: • $542.79 as a balance • Roderick Feckelbocker as the owner’s name
Creating your own classes class Elephant(object): def __init__(self, name, age, weight): self.name = name self.age = age self.weight = weight • We now have a class of Elephants • Elephants starts with a capital letter • Our Elephants all have names and ages. • __init__: • __init__() is always the constructor in Python • The two __ on both sides of the word init indicate that it is a special name • Constructor is automatically invoked when an object of this type is created.
Creating an Elephant named Rita: class Elephant(object): def __init__(self, name, age, weight): self.name = name self.age = age self.weight = weight elephant1 = Elephant("Rita",32,6080) print("The Elephant’s name is " + elephant1.name + "and her age is " + str(elephant1.age)) elephant2 = Elephant("Harold",28,7940) print("The Elephant’s name is " + elephant2.name + "and his age is " + str(elephant2.age))
How much food should Rita get? from math import * class Elephant(object): def __init__(self, name, age, weight): self.name = name self.age = age self.weight = weight #The pounds of food an elephant gets is calculated by their weight – (their age * 2.5 deffeedvol(self): # Notice this is still part of the Elephant class! return(self.weight – (self.age * 2.5)) elephant1 = Elephant("Rita",32,6080) print("The Elephant's name is " + elephant1.name + "and her age is " + str(elephant1.age)) print(“ She should get " + str(elephant1.feedvol() ) + " pounds of food per day ")
Classes • You are, in essence, creating your own type: • Think of Lists: • Lists have elements in them. • Lists also have methods (functions) that work specifically on lists in a certain way: • List.pop() • List.index() • List.sort() • Etc. • All the above are methods that work in a specific way on lists of items. • We’re now creating our own types • Our types will have their own properties • And they will have methods (aka functions) that work in a specific way on objects that of the type of our class. • How do we know if it should be a class? • Is the data related to a single concept? (e.g., a student, an airline ticket, a car) • See if you can take the data you’re working with and organize it into classes
Example: Can you write a class for a rectangle (with width and height properties?) class Rectangle(object): def __init__(self, width, height): #[CONSTRUCTOR] self.width = width self.height = height Can you make a rectangle? #main rectangle1 = Rectangle(10, 10) #[EXAMPLES] rectangle2 = Rectangle(20, 5)
Questions: what functions should operate on objects made from the class? class Rectangle(object): def__init__(self, x, y): self.width= x self.height= y defarea(self): return (self.width * self.height) x=Rectangle(10,5) print(Rectangle(10,5).area()) • Note the parameters that go into the method area • widthandheightare properties of every object created with the Rectangle class • We don’t need to pass them into any method that belongs to the class • We do need to pass in parameters that aren’t properties of objects created with the class.
Altogether: class Rectangle(object): def __init__(self, width, height): self.width = width self.height= height def area(self): return self.width * self.height rectangle1 = Rectangle(10, 10) #[EXAMPLES] rectangle2 = Rectangle(20, 5) print(rectangle1.area()) print(rectangle2.area()) print(Rectangle(6,8).area())
Methods needing outside parameters: class Rectangle(object): def __init__(self, width, height): #[CONSTRUCTOR] self.width = width self.height = height def area(self): return self.width * self.height def boxvol(self,x): return self.width * self.height * x rectangle1 = Rectangle(10, 10) #[EXAMPLES] rectangle2 = Rectangle(20, 5) print(rectangle1.area()) print(rectangle2.boxvol(2)) print(Rectangle(6,8).area())
What about properties that we don’t know ahead of time? What properties should belong to a circle class? class Circle(object): def__init__(self, radius): self.radius= radius self.area=??? self.circumference=??? Question: When we create an object of type Circle, how can we set the specific value of the area and the circumference These are based on the radius We need to set the radius property before we can set the area or the circumference property.
Can we include in the class a function that checks if this circle is bigger than another circle? What type should it return? from math import * class Circle(object): def __init__(self,radius): self.radius = radius self.circumference = self.getcirc() self.area = self.getarea() def getcirc(self): return(self.radius * 2 * pi) def getarea(self): return(self.radius **2 * pi) circ1 = Circle(3) print(circ1.area) print(circ1.circumference)
from math import * class Circle(object): def __init__(self,radius): self.radius = radius self.circumference = self.getcirc() self.area = self.getarea() def getcirc(self): return(self.radius * 2 * pi) def getarea(self): return(self.radius **2 * pi) def isbigger(self, circle2): return(self.area > circle2.area) firstcirc = Circle(3) secondcirc = Circle(4) thirdcirc = Circle(2) print(firstcirc.area) print(firstcirc.isbigger(secondcirc)) print(firstcirc.isbigger(thirdcirc))
Classes Examples: • Student? • What properties? • What methods? • Deck of cards? • Maybe this needs 2 classes?
Classes that use other classes… • Student Class: name (last, first), lab grade, exam grade, project grade • Student’s methods: getgrade-calculates student’s grade • labs are worth 25%, • exams are worth 50%, • projects are worth 25% class Student(object): def __init__(self,firstname,lastname,lab,exam,project): self.first = firstname self.last = lastname self.lab = lab self.exam = exam self.project = project self.grade = self.getgrade() defgetgrade(self): x= self.lab * 0.25 + self.exam * 0.5 + self.project * 0.25 print(self.last + "grade is " + str(x)) return(x)
Now let’s make a class for classes • Roster of students • Gradelist • Average grade
class Classroom(object): def __init__(self,roster): self.roster = roster self.gradelist = self.getgradelist() self.classave = self.getave() defgetgradelist(self): ls = [] for x in self.roster: ls.append(x.getgrade()) return(ls) #get class average? defgetave(self): x = sum(self.gradelist) return(x/len(self.gradelist)) class Student(object): def __init__(self,firstname,lastname,lab,exam,project): self.first = firstname self.last = lastname self.lab = lab self.exam = exam self.project = project self.grade = self.getgrade() defgetgrade(self): x= self.lab* 0.25 x +=self.exam* 0.5 + self.project* 0.25 print(self.last + "grade is " + str(x)) return(x) classlist = [ Student(‘Bill','Williams',88,76,94), Student(‘Anne','Stewart',97,67,73), Student(‘Bert','Jones',88,24,56), Student(‘Mary','Smith',78,93,42)] cis106 = Classroom(classlist) Question: How do you know which getgrade method to use? cis106.getgrade() cis106.roster[2].getgrade()
Printing an object bert = Student('Bert','Jones',88,24,56) print (bert) Results? <__main__.Student instance at 0x02CA3648> Probably not what we want we probably want to print out a Student object’s properties (name, lab, exam, project) We may want to print out the Student’s final grade We need to write our own code for what should be printed out for a student object.
Creating String: class Student(object): def __init__(self,firstname,lastname,lab,exam,project): self.firstname = firstname self.lastname = lastname self.lab = lab self.exam = exam self.project = project defgetgrade(self): x= self.lab * 0.25 + self.exam * 0.5 + self.project * 0.25 return(x) def__str__(self): x = "Name: " + self.firstname + " " + self.lastname + "\n" x += "Lab: " + str(self.lab) + " Exam: " + str(self.exam) + " Project: " + str(self.project) + "\n" x += "Final Grade: " + self.getlettergrade() + "\n" return(x) defgetlettergrade(self): y = self.getgrade() if y > 90: return("A") elif y > 80: return("B") elif y > 70: return("C") elif y > 60: return("D") else: return("F")
def __str__(self): #inide the class definition) x = "Name: " + self.firstname + " " + self.lastname + "\n" x += "Lab: " + str(self.lab) + " Exam: " + str(self.exam) x += " Project: " + str(self.project) + "\n" x += "Final Grade: " + self.getlettergrade() + "\n" return(x) #main bert = Student('Bert','Jones',88,24,56) print (bert) >>> Name: Bert Jones Lab: 88 Exam: 24 Project: 56 Final Grade: F >>>
Printing list of students: classlist = [ Student(‘Bill','Williams',88,76,94), Student(‘Anne','Stewart',97,67,73), Student(‘Bert','Jones',88,24,56),Student(‘Mary','Smith',78,93,42)] for x in classlist: print(x) Name: Bill Williams Lab: 88 Exam: 76 Project: 94 Final Grade: B Name: Anne Stewart Lab: 97 Exam: 67 Project: 73 Final Grade: C Name: Bert Jones Lab: 88 Exam: 24 Project: 56 Final Grade: F Name: Mary Smith Lab: 78 Exam: 93 Project: 42 Final Grade: C
Evaluating Code Efficiency: Algorithm Analysis • What is the task to be accomplished? • Calculate the average grade for a given student • Finding the nth element in a sequence • What are the time / space requirements ?
Algorithm Analysis • Algorithm: Finite set of instructions that, if followed, accomplishes a particular task. Algorithm Analysis: • Space complexity • How much space is required • Time complexity • How much time does it take to run the algorithm • We worry about Time Complexity! • We deal with estimates! • Makes life a lot easier
Time Complexity • Often more important than space complexity • More and more space available • time is still a problem • researchers estimate that the computation of various transformations for 1 single DNA chain for one single protein on a1 THZ computer would take about 1 year to run to completion • Algorithms running time is an important issue
Running time • We can evaluate for the worst case, average case, or best case. • Suppose the program includes an if statement that may execute or not: • variable running time • We assume that the worst case will run! • Typically algorithms are measured by their worst case (big-Oh)
Worst Case Running Time • Evaluates the algorithms independent of the hardware and software • Determine the running time of an algorithm using generalities
Algorithm Analysis • Analyze in terms of Primitive Operations: • e.g., • An addition = 1 operation • Assignment = 1 operation • Calling a function or returning from a function = 1 operation • Index in an array = 1 operation • Comparison = 1 operation • Analysis: count the number of primitive operations executed by the algorithm • remember, we count the worst case scenario!
What does this function do? • def ourFunc(ls) • x= ls[0] • y = 0 • for ct in range(1,len(ls)): • if x < ls[ct]: • x = ls[ct] • y = ct • return(x) How many operations ? Line 1: 1 counts Line 2: 2 count Line 3: 1 count; Line 4: 2*(list length – 1) Line 5: 2 * (list length – 1) Line 6: 2 * (list length – 1) Line 7: 1 * (list length – 1) Line 8: 1 (could be considered 2) Total: 1 + 2 + 1 + 7*(list length – 1) + 1 = 7*listlength - 2 • An addition = 1 operation • Assignment = 1 operation • Calling a function or returning from a function = 1 operation • Index in an array = 1 operation • Comparison = 1 operation
Algorithm Analysis • We simplify the analysis bygetting rid of unneeded information • We drop constants. • E.g., if we have a program that runs in 3n +2 time, we’d say that the function runs in worst case O(n). • We drop lower order terms • E.g., a function that runs in polynomial time: • (4n4 + 300n3 +7n + 2), • Runs in worst case O(n4). • Why? Because after a certain point the lower order is subsumed by the higher order. • e.g., if n is 500, it becomes so much more of a time concern than the 300n3 that we really don’t have to worry about it. Same with 7n. • Hence we get O(n4) for this polynomial.
We get rid of unneeded information • We drop constants • We drop lower order terms • defourFunc(ls) • x= ls[0] • y = 0 • for ct in range(1,len(ls)): • if x < ls[ct]: • x = ls[ct] • y = ct • return(x) How many operations ? Total: 1 + 2 + 1 + 7*(list length – 1) + 1 = 7*listlength - 2
Alg Analysis? • We get rid of unneeded information • We drop constants • We drop lower order terms def f(x): for j in range(x): for k in range(x): print(j*k) • Running time? def f(x): for j in range(0,x): for k in range(0,x): for l in range(0,x): print largest(j,k,l) • Running time?
Algorithm Analysis? def f(x): if x %3 == 0: while x > 0: k = x * 3 l = k *x x = x-1 else: k = 0 while k < x: L = 0 while l < x: m = k + l l += 1 k += 1 return(3)
Search • Find where num x is in a sorted list: • list = [1,3,6,8,9,11,13,16,19,23,26,27,34,37,42,45] • Find 3? • Find 23? • Find 45?
B Search ls = [1,3,4,6,8,10,11,15,17,22,26,28,34,46,52,57] index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 How long to find 11? How about 57? How about 1? Log n: for some n that is between 2x-1 and 2x in length, it will take at most x steps to accomplish the task (above: 16 items, 24, it takes at most 4 attempts to find the number.
Better Search: • If list is sorted, look at middle value in list. • If num == middle value, we’ve found our num • If num>middle value, look at top half of list • If num < middle value, look at bottom half of list • We repeat this until we either find the value or we know the value isn’t in the list.
Now BinarySearch [3,4,7,8,10,11,13,19,22,25,32,36,41,44,45] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 To search for 7: First look at 19 in location 7 (1 check) Then look at 8 in location 3 (2 check) Then look at 4 in location 1 (3 check) Then look at 7 in location 2 (4 check) We’re done. So with 15 numbers, AT MOST we must look at 4 values Or for anything less than 16 values, we must do at most 4 checks 16 =24 The log of 16 is 4, or log 16 = 4 Thus for n values in an array, we must do at most log n checks to find the value
Now BinarySearch [3,4,7,8,10,11,13] 0 1 2 3 4 5 6 To search for : First look at 8 in location 3 (1 check) Then look at 11 in location 5 (2 check) Then look at 10 in location 4 (3 check) We’re done. So with 7 numbers, AT MOST we must look at 3 values Or for between 4 and 7 values, we must do at most 3 checks 8 =23 The log of 8 is 3, or log 8 = 3 Thus for n values in an array, we must do at most log n checks to find the value
One more time: [3,4,7,8,10,11,13,19,22,25,32,36,41,44,45,46,48,49,50,51,53,57,58,62,64,65,66,69,71,72,74] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 Looking for 13: Step 1: Look at 46 in location 15 Step 2: Look at 19 in location 7 Step 3: Look at 8 in location 3 Step 4: Look at 11 in location 5 Step 5: Look at 13 in location 6 So with 31 numbers, AT MOST we must look at 5 values Or for between 16 and 31 values, we must do at most 5 checks 32 =25 The log of 32 is 5, or log 32 = 5 Thus for n values in an array, we must do at most log n checks to find the value
def binseait(ls,num): x = -1 y = len(ls)/2 first,last = 0,len(ls)-1 while (first <= last): print ('first is '+str(first)+'last is '+str(last)) if ls[y] == num: x = y first = last+1 elifls[y] < num: first = y+1 else: last = y-1 y = first + ((last-first)/2) return(x) print(binseait(list,16)) def binsearec(ls,num,ind): print ('ls is now: ' + str(ls)) if len(ls) == 0: return(-1) elif (len(ls) == 1) and (ls[0]== num): return (ind) elif (len(ls) == 1): return (-1) x = len(ls)/2 if ls[x] == num: return(ind + x) elifls[x] > num: return binsearec(ls[0:x-1],num,ind) else: return(binsearec(ls[x+1:len(ls)],num,ind+x+1)) list = [1,3,6,8,9,11,13,16,19,23,26,27,34,37,42,45] print(binsearec(list,45,0))
Remember our studentclass? class Student(object): def __init__(self,firstname,lastname,lab,exam,project): self.firstname = firstname self.lastname = lastname self.lab = lab self.exam = exam self.project = project self.grade = self.getgrade() defgetgrade(self): x= self.lab * 0.25 + self.exam * 0.5 + self.project * 0.25 return(x)
class Student(object): def __init__(self,first,last,lab,exam,proj): self.firstname = firstn self.lastname = last self.lab = lab self.exam = exam self.project = proj self.grade = self.getgrade() defgetgrade(self): x= self.lab * 0.25+self.exam*0.5+self.project*0.25 return(x) def__str__(self): new = self.firstname+ " " + self.lastname+ " " + str(self.grade) return(new) class Classroom(object): def __init__(self,roster): self.roster= roster self.gradelist = self.getgrades() defprintclass(self): for x in self.roster: print (x) defgetgrades(self): ls = [] for x in self.roster: ls.append(x.grade) return(ls) defclassave(self): return(sum(self.gradelist)/len(self.gradelist)) cis106 =Classroom([Student('Bill','Williams',88,76,94),Student('Anne','Stewart',97,67,73), Student('Bert','Jones',88,24,56), Student('Mary','Smith',78,93,42) Student('John','Martin',86,57,92), Student('Wilma','Lewis',76,67,78)])
Write a method to find a particular student’s grade in a class: class Student(object): def __init__(self,first,last,lab,exam,proj): self.firstname = first self.lastname = last self.lab = lab self.exam = exam self.project = proj self.grade = self.getgrade() defgetgrade(self): x= self.lab * 0.25+self.exam*0.5+self.project*0.25 return(x) def__str__(self): new = self.firstname+ " " + self.lastame+ " " + str(self.grade) return(new) class Classroom(object): def __init__(self,roster): self.roster= roster self.gradelist = self.getgrades() defgetgrades(self): ls = [] for x in self.roster: ls.append(x.grade) return(ls) deffindstudent(self,last,first): for x in self.roster: if x.last == last: if x.first == first: print(x) return print("student not found") return defclassave(self): return(sum(self.gradelist)/len(self.gradelist)) cis106 =Classroom([Student('Bill','Williams',88,76,94),Student('Anne','Stewart',97,67,73), Student('Bert','Jones',88,24,56), Student('Mary','Smith',78,93,42) Student('John','Martin',86,57,92), Student('Wilma','Lewis',76,67,78)])
How about a deck of cards? • Class for card? class Card(object): def __init__(self,suit,face): self.suit = suit self.face = face • Class for deck? Get a random card? class DeckofCards(object): def __init__(self,deck): self.deck = deck defgetcard(self): x = randrange(0,len(self.deck)) return(self.deck[x]) Currdeck = DeckofCards([Card(‘C’,1),Card(‘C’,2),Card(‘C’,3),Card(‘C’,4),Card(‘C’,5),Card(‘C’,6),Card(C’,7)…]) • Or: class DeckofCards(object): def __init__(self,listofsuits,listoffaces): self.deck = self.getdeck(listofsuits,listoffaces) defgetdeck(self,ls,lf): newdeck = [] for x in ls: for y in lf: newdeck.append(Card(x,y)) return(newdeck) defgetcard(self): x = randrange(0,len(self.deck)) return(self.deck[x]) currdeck=DeckofCards([‘C’,’S’,’H’,’D’],[1,2,3,4,5,6,7,8,9,10.11.12,13])
Now, how about 7Card Stud? Class for card? class Card(object): def __init__(self,suit,face): self.suit = suit self.face = face Class for deck class DeckofCards(object): def __init__(self,listofsuits,listoffaces): self.deck = self.getdeck(listofsuits,listoffaces) defgetdeck(self,ls,lf): newdeck = [] for x in ls: for y in lf: newdeck.append(Card(x,y)) return(newdeck) defgetcard(self): x = randrange(0,len(self.deck)) return(self.deck[x]) • a gethand method (that creates a list of 7 random cards) • A curhandproperty (that calls gethand to get a list of 7 cards) • A findlargest method that finds the largest value in the currhand (just using faces, not suits)
Class for card? class Card(object): def __init__(self,suit,face): self.suit = suit self.face = face def __str__(self): return(str(self.face)+self.suit) class DeckofCards(object): def __init__(self,listofsuits,listoffaces): self.deck = self.getdeck(listofsuits,listoffaces) self.currhand = self.gethand() defgetdeck(self,ls,lf): newdeck = [] for x in ls: for y in lf: newdeck.append(Card(x,y)) return(newdeck) defgetcard(self): x = randrange(0,len(self.deck)) return(self.deck[x]) defgethand(self): ls = [] for x in range(7): ls.append(self.getcard()) return(ls) defgethighest(self): y = -1 for x in self.currhand: if x.face > y: y = x.face card = x print(card) deck = DeckofCards(['C','D','H','S'],[1,2,3,4,5,6,7,8,9,10,11,12,13]) deck.gethighest()