How does the program know other objects? Is it just from the importing?

Yes, it is from importing. Python defaults to importing a bunch of built-in classes (e.g., lists, strings) so we don’t have to import them. But anytime you want to reuse code written a Python file, you need to import it. This is a common feature of all programming languages.

Who are you rooting for in the NBA finals

I don’t watch the NBA much anymore since my childhood team (Detroit Pistons) has been mediocre for about 15 years. I like close games and upsets, so anyone but the Warriors :)

Is there any reason to use for i in range(len(hand)) over for card in hand?

Good question - I thought about that as I was writing it. In that example, both work the same; the latter option is simpler, while the former is more flexible in that it allows us to use i for other purposes (e.g., print iteration number, index into a parallel list, etc.)

Are classes the way that we can create more complex data structures? Or is there a better way to define a new object?

Yes, that is correct! In fact, in CS35, all of the data structures you build are defined as classes/objects.

Syntax question: is it bad programming practice to return and assign tuples? ie function() has a return statement return 3, 4 and in main a,b = function()

That is a common usage in Python (and a powerful aspect of the language). I don’t like to teach it right away for two reasons. 1) It is not a common feature in other languages, so it helps to think about other ways to accomplish that goal that will work in other environments. 2) It requires mastering the basic firsts, which is my primary goal as a teacher. Otherwise, it can lead to very buggy and difficult to understand programs.

since we had to create the card and deck and blackjackhand classes, did we really do less coding in the oop way?

This is a good point. We didn’t code less, but our code is more abstracted (easier to delineate, update, and debug the components). It is also reusable. If we had more time, we could have written a program for a different card game like euchre or hearts and reused much of the work (especially Deck and Card; our value functions would be obsolete).

Will the getters ever become more complicated than just returning the variable?

They are usually straightforward. You may need to do a few calculations, thought. For example, on the Team exercise, getWinPercent required returning information that wasn’t a data member - we had to check for divide by 0 and then calculate the percentage.

What are the advantages to using classes in blackjack.py rather than our week 7 program with only functions?

Reusability - Deck and Card are concepts independent of blackjack; you could imagined writing additional games that need to use the same concept. Readability due to encapsulation and abstraction - objects encapsulate certain ideas and so they can be easier to understand. Most programs are a mixture of objects and imperative programming - so its not like we advocate making everything an object. But it can be a very powerful tool.

Can you call the various classes by using an upper or lower case version of what you have named them?

It is case sensitive. So card will not be recognized as the class Card

What other programs that we have done can be better done with OOP?

Instead of doing a list of lists for the Zoo lab, we could write a Animal class and store all the features as data members. You would write a toString() method that would take care of printing out the attributes of an animal (i.e., after searching and finding an animal by name). You could also have the Animal class calculate the dangerous feature internally.

why in the __init__we have to set self.name = name or self.number = year (or whatever it may be) if we don’t use those variable names again (in getName, we return self.name and not the name variable)

name and year are the parameters to the __init__ function. Their scope is the __init__ function and are lost after that is complete. The only way to preserve that information is to make it a data member of the object as we did by setting self.name = name. So, if we ever want to refer back to the original name variable, it is stored in self.name for us to reference (as we do in the methods you outline).

Is it always better to use object-oriented programming over the imperative method?

Nope! Just as we wouldn’t store a single int in a list, we don’t need to turn the simplest of concepts into an object.

Are there any downsides to using a lot of classes?

It is work to write, debug, and update them. If we only need them one time, it is more effort than is needed. It can also be hard to encapsulate all of the ideas needed into one class. For example, you might want to write a class called Student. Should it encapsulate all students, including auditors, special students, transfer students, etc? Or should those be different classes? While I would still consider using objects in this scenario, I would need to analyze the design carefully.

What are the difference in runtimes for our two blackjack programs?

I don’t think it should change significantly since we didn’t make any of the functionality do extra work. There may be cases where abstracting too much detail can create inefficiencies.

Can you import multiple classes in a program?

Yes! We do this in the blackjack example, where we import the Card and Deck class from card.py as well as the BlackjackHand class. You did this with graphics - you imported Circle, Rectangle, random, etc. all in one program.

Is there a limit to the number of classes you can make in a program?

Not that I’ve ever seen!