Computer Science 61A - Lecture 15

Uploaded by UCBerkeley on 01.10.2012

JOHN DENERO: It is October! STUDENT: Yeah!
JOHN DENERO: September is gone. STUDENT: Oh.
JOHN DENERO: All things that were due in September have already passed. Now we have some things
due in October. 1 of which is project 2 is due this Wednesday.
That's October third.
Homework 5 due Friday that's October fifth.
I also wanted to point out that you should haveÊ can everyone hear me in the backÊ
you should have received an e mail. Your readers who have now finished given comments about
project 1. Hold office hours to discuss those with you or general points about style or
way to see write programs more effectively. So they have office hours. You can find their
individual Web pages linked from the main staff page. And go to 1 of their appointments
to see how it goes. Hopefully it will be useful you can have direct 1 on 1 tips, mentoring,
advice, whatever you want. Is anyone already gone to a reader office
hour? I think there haven't been any yet. So that's
good [LAUGHTER].
Questions about the project, homework? STUDENT: You still gotten an e mail from your
reader with feedback. Now is a great time the e mail your TA feel free to copy me and
stay what's going on and we'll track it down for you.
Question is: what happens when you submit project 2. You can submit now. The autograder
might be running this moment but I don't know that it is. But our goal so to have it running
tonight. So it will really run the doctests that have been provided to you and tell you
that we've received your submission correctly. You will eventually get an e mail if you submit.
STUDENT: Can you upload more Mac. JOHN DENERO: Maps for the project I'll do
that tonight absolutely. STUDENT: More maps.
(INAUDIBLE). When I saw perking.
JOHN DENERO: More maps already exists. I've learned they exist if you dig in Piazza. But
I'll make sure they are there in the pin so you can see them.
So I will read you 1 topic from last time because I tried to squeeze it in the last
2Êminutes of lecture. And I'm sure people don't learn then. So what's a dispatch dictionary?
This was our way of bundling together a bunch of behavior that shared a common state.
So we are getting to the point where we have some common local state like the balance of
bank account is example we will keep referring to.
And we have multiple different functions that all might go and check the balance or change
it in some way. And we want to have all these functions bundled together along with the
balance in so coherent representation of a bank account.
1 way to do that is with dispatch dictionary which is a regular dictionary but we are have
a special structure to it. It's keys are going to be strings. Which name
either functions that access that local shared state or that actually hold the values that
are the local shared states themselves. So let's build a local dictionary that represent
as bank account together. I will create with a function calledÊ"account". What does it
have? Well, it will have a dictionary, which we'll call dispatch. That's holding the balance
of the account. Which will start at $0. That's actually what I return from this function.
Every time I create account I create new dictionary. It holds a balance. But also needs to hold
the behavior associated with the bank account. Which is that we need to be able to withdraw
and deposit money in and out. So how do we withdraw some amount of money?
From a bank account? What we do is check and see if that amount is greater than the current
balance, which we can look up by referring to the special dictionary itself and checking
the balance. If that's the case then we want to returnÊ"insufficient funds".
You are broke. If that's not the case we haven't returned
now we change the dispatch dictionary. By changing the balance so it's less than it
was before. Here I assume an amount is non negative we can of course but assert statement
but we'll leave out for the moment. So subtract the amount and then return the balance.
Notice the way I'm using this dispatch dictionary itself containing the data that we are updating
with withdraw function and also which we return. How do I deposit? That's a related behavior
where all we do is change the balance to be more than it was before, and then we'll return
that balance.
How am I doing? I have some dictionary which holds the balance. I have some way of withdrawing
money and some way of depositing money both things refer to the balance that seems good.
But once I return from this function I can't access withdraw or deposit anymore. The problem
is I haven't created a mechanism for referring to those things. That mechanism is going to
be put them along with data right here inside the dispatch dictionary.
If you want to stop lines from getting long there's nothing wrong with putting each key
value pair on different line. Okay let's make this just a bit bigger. There's
our account. I create a new account. I can check its balance by looking it up directly.
I can withdraw $5 from it. Actually I can't because I have insufficient funds. So if I
deposit a hundred dollars, then I can start withdrawing whenever I have hundred dollars
in my account I immediately withdraw like crazy and then I check the balance I have
$10. We have coupled the behavior of depositing and withdrawing and checking the balance itself
altogether in a dictionary. That'ses what we call aÊ"special dictionary."
Questions about that? Okay a lot of good ideas are packed into this example. Bundling together
behavior and shared local state of a bunch of functions that all need the access and
perhaps mod if you the same balance. And we have 1 coherent representation of the
bank account which is A. A looks a little bit hard to interpret. So
that's unfortunate. It's this big long line when printing it out. There are other things
that could be better we refer the special balance up here but don't find till there
we can't move up there's an up and down scanning you have to do to read the program if it's
best to read from top to bottom that's unfortunate. Another unfortunate thing about implementation
we are repetitive so we said name withdraw is withdraw which should be built in to the
language but in this case it's not we have to say what's the string that give it is function
that withdraws. And we have to build that in.
Other than that it seems like a reasonable way of creating accounts. This is basically
object oriented programming is 1 of my favorite topics in this course. Why? It takes a bunch
of good ideas and doesn't just say please use them together at the same time.
It instead, extends the programming language to make it easy to use all these good ideas
together at the same time. And that's a really keen invention that means
everyone use the ideas at the same time because all the sudden the programming language we
use is supports us doing this quickly and efficiently. So what do we know about data
so far and the kinds of things we want in the programming language. 1 is distraction.
(On screen). Abstract data type off valid representation of data type if you satisfied
some behavior conditions of it's not about the lay out of the actual information whether
tuple or not whether it behaves like the thing we are trying the represent.
There is message passing which says we want to organize programs as a bunch of modular
components that pass messages to each other. And thereby create complex computations where
we have a bunch of different objects talking to each other. Each of which is responsible
for maintaining its own local state and knowing about its own behavior.
And we have the idea of dispatch functions or dispatch dictionaries where it's 1 thing
in our program can encapsulate a bunch of different behaviors that all affect the same
shared local state. Those are all our 4 good ideas.
We could do this all with functions and assignment we've done it before but now we will do it
in a easier prettier way. And more convenient the access all these ideas at the same time
and that's what object oriented programming is. (On screen)it enforces abstraction barriers
allows message passing. Bubbles together information and related behavior. It does good things
and by doing so it let's us think about our programs metaphorically as having the state
of our program that is what the are tall balance of accounts in the world distributed among
many objects instead of 1 big global frame listing everyone's account balance of this
is we have many different accounts each of which contains its own balance. That's how
we distribute the state of program locally among each objects. Each (On screen) what
to do with local state. Whether it's allowed to withdraw the funds you ask it to withdraw
or whether you've gone broke. Last part of metaphor you might have multiple
different object that are in fact of same instances of same type of thing therefore
you can expect them to behavior the same even if different objects.
The last piece we might have different types of things that relate to each other. There's
a tax on my of all things in your program and some of them relate to each other in various
ways and then we will have different statements specialized statements different vocabularies
that really support the metaphor and allow us to use seamlessly and let's communicate
with each other. It's hot.
STUDENT: Yeah. JOHN DENERO: Okay not the room. But object
oriented programming is hot [LAUGHTER]. JOHN DENERO: So the backbone of object oriented
program issing introducing new user defined classes so that's new types of things.
A class serves as a template for instance all things that are related to the same class
that have the same type of. The idea is if we want to talk about becomes they should
all have common attributes a balance tells how much money there. An account holder who
actually owns the account. And the account class to the type itself should be responsible
for making sure all instances have these attributes. The way it looks like in the syntax of the
language. Is that account with capital A is a class. It doesn't have to be capitalized
but convention we typically capitalize classes and bind to A and pass in gym as the name
of the account holder. Now we have an account. We can look upholder
with dot expression and look up its balance. Currently gym has no money.
The account classes is responsible forever making sure as soon as I create an account
it has an holder and balance. They should all have same withdraw and depositing things
that are built in that we can do to accounts and we should be able to deposit 15 into A
with syntax A.deposit 15. So this sends a message the please deposit 15 into your account.
We can withdraw at which point we'll return the remaining balance and we can look up that
balance see that it's changed. That's a good idea they should all share the same behavior
that's a good idea. The even betterÊ Jim got crazy ride the withdraw
too much. The even better idea is in fact not only o
do they share the same behavior but function too. There can only with be 1 withdraw function
that gets used regardless of which instance this class we withdraw from.
That's what classes are meant to do. How they are meant to serve us in programming language.
Here's how we create them: With the class statement.
The classiest statement of all. STUDENT: Ha ha.
JOHN DENERO: What you write is classes and name of class which is typically capitalized
then parentheses you add a base class that's another class and follow with a suite. Base
class is next lecture. So you may be wondering what it does and why
it's there. Keep on wondering I like suspense. A class statement creates a new class which
is an object. It's a value in our language. Like a function is value if language we can
pass it around or pass classes too. So there are first class obtains in the language in
this case we bind to new class to the name we provided in the first framework current
environment is class statements is kind of like a def statement it creates a new thing
and binds it to a name. Then we have the suite what's there. It's
full of statements TOI just assignment statements and def statements. And those create attributes
of the class. Attribute of a class is a named thing that's
contained within the class. Classes themselves have a bunch of names bound to some values.
So classes in many ways are like frames in terms of their internal structure. They have
names in values. But in this case a class has names which we call attribute names. And
the values we callÊ"attributes". As soon as an instance is created that means
we create a new account. Itself. We created the class of all accounts and create a new
account. We pass that thing to a special function called in it. __INIT__is the name of attribute
of this class. It's special. Whenever you see double underscore that means this name
has special significance. It's behaving in particular way that's predefined by language.
The language is very opinionated in this case. It says what it means to have class is there's
a special way of creating and initializing new instances of class. And opinionated software
can be good it drives everybody using it to program the same way that's the idea behind
object oriented to give guidelines to write programs that many people share.
1 guideline we have functions in Python called underscore underscore init which are called
the constructors of the class. How I create an account class is like this:
I would say here's 1 class statement. Class account. I will write object here and not
tell you why because that's next lecture. Then I defined and init function.
Here's something else special I always use the wordÊ"self "adds first formal parameter
of this function and then I can have other formal parameters as well. Inside the body
of init function, I have written down things that look like assignment statements kept
with dot expression on the left hand side. Here we say this new account I created, it's
balance is 0. And its holder is the account holder I passed in.
So there's actually a lot going on in this snippet of code that might not all makes sense.
So hang on let me walk through the details of what happens when I write this down and
then feel free to ask a bunch questions. But this is code that will run to create a
new class that contains account objects. Okay so the most important thing happening
here is initialization. What happens when I create a new object which is an instance
of this class? That means it's a new thing and what we know about it it's an account.
So what happens here's the idea all becomes should have balance and account holder and
account class should add attributes in to make sure they exist. Here was the example
before I created an account for Jim what's the holder it was Jim what's the balance Jim
is broke it's 0. When a class is called. So what happened here
is I created an account class and then I called it just like a call expression.
So it is just a call expression. I evaluate the operate and the operands I apply. That
which is the value of operate to the value of operands as arms. But now I don't have
a function as operate I have a class as the function that I would apply.
And classes are a little bit different. They kind of look when they get applied liked functions.
But there's a special rule that says: here's what happens when the value of the operates
expression is a class. The first thing is a new instance of that
class is created. That thing it's a blank slate. It has no attributes within it. Except
for this telephone numbers what its class is telephone numbers it's an instance of account
but doesn't have a balance yet or account holder. It has no particular attributes at
all. Sorry that's a really bad picture of a blank
slate. And then what happens is that we use the magic
of the underscore underscore init underscore underscore function. Here's special behavior.
This constructor function of the class is then calledÊ it's just a functionÊ alled
with new object we created as its first argument. And we always use the nameÊ"self "as parameter
that binds to that argument and then we pass in additional arguments vied in call expression
used to create the object. Remember here was the code to define the class. I have to do
that first then I create a new account. When I call the account what happens is I create
a new account object. Then I pass it in to the init function.
As the self parameter. And I'm also passing in whatever else I included
as an argument in this call expression. In this case Jim gets passed in as account holder.
So I call account with 1 thing. Which in the end, calls init of the account class with
2 arguments the blank slate account itself and also the name of the account holder.
And then we execute the body of this function so self is new object. We set balance to 0
we set holder to account holder and now we have something we can use. This all happens
automatically. Init is automatically you don't have the explicitly call it even though you
create new object you will go and try to find an init function.
Woo! Questions. JOHN DENERO: If init is called automatically
how is it fed the account holder name. JOHN DENERO: How does all the machinery happen.
These are just the rules of how classes work. You create the object. Here's the call that
creates the object is account Jim. What happens when you make that call? Is you
create new independent stance but still remembered that you passed in Jim that gets routed down
and put in as extra argument into the init function.
STUDENT: What happens if you don't pass itself as first argument.
JOHN DENERO: What about this name self. What happens if you change it. Python will still
run it doesn't have to be called self it's just another name in language. But this is
a very strong convention like everybody uses self. So don't goat too crazy.
Is self equivalent to super in Java is that like the same thing.
JOHN DENERO: Is this equivalent to anything in Java. And no. This is just a name we bind
to object so that we refer to it. Java does a different thing in that it kind of hides
self altogether. Most other programming languages aren't as explicit as this but we do and it
makes code easier to read. STUDENT:
JOHN DENERO: Question is can you have multiple different constructors that might depend on
different numbers of arms no but you can of course have default values because init is
just a function so there are way to make it behave differently depending on how many arguments
you pass. Self is just the name of object you just created.
Can you pass in a function? You mean up here instead of Jim.
STUDENT: Yeah. JOHN DENERO: Yeah you can pass anything you
want and it will be passed the init function just like any other function. It's very flexible
for creating new obtains it happens to be when you have the operate as class you will
foal this recipe. STUDENT: Why is account capitalized it doesn't have to be
it's a convention most classes are capitalized to keep distinguishing from their instances.
Follow this recipe. I think the question was: can we another name
besides self yes, but never do. Let's write down this code and take a look.
There was our old account. Let's make it big. Here's our new way of kind of saying the same
thing. I create an account oh sorry Woo!. Making a mess.
I make a class calledÊ"account" what does it have within it? Well, it is an init function,
which is part of the account class. Which does things like say self .balance = 0.
And self .Ê I'm making a mess this was account holder in the example I had before.
Okay so this was equivalent to when before we had written any of this stuff. All we really
had was a balance in here. And now we've defined up here in our original
example with dispatch dictionaries to new functions I think we need to learn how to
do that with accounts as well. And then some of the ideas of how we use these things should
come together quickly.
JOHN DENERO: Question is: does init return none. You never use the init return value
at all. I guess is important thing is that init function
doesn't need the return the object it's the object was created it gets passed to init
in order to gain attributes. And that is the value of this call expression account Jim
which is bound to A it's always the new object that's created which is in the instance of
the account.
STUDENT: Is self and defined somewhere. (INAUDIBLE).
JOHN DENERO: Good question. But we'll get to it.
Question is: A at the top here and self both at different times get bound to the same object
which is the new object created. So object created passed to init now it has attributes
returned from call expression. Now it's bound to A.
So going back the some of our themesÊ 1 more question.
Question is: Certainly you can pass as many argument you want they will be included o
self function. We'll move on.
1 thing to note is that a new object created every time we call an account.
So every object is instance of user defined class has unique identity the create Jim's
and Jack's account and test we learn A is A and A is not B. So all these things are
different but of course binding object to new name using assignment doesn't create new
object. If I say C is still A. New accounts call expression evaluates to the a class.
That's how I create things. Now the thing that makes this interesting are the methods.
These are the behaviors associated with data values that we want to bundle together. This
is withdrawing and depositing. So methods are defined in the suite of a class statement
via def statements. So I have that init, which sets up an object to make sure it has the
right attributes the balance and holder and then I can define a deposit function.
Now, it looks just like a function definition. It in fact creates just a regular function.
The only thing that makes it aÊ"method" instead of function is that it's part of a class it's
the attribute of class. Methods are just functions that are attributes of class defined within
a class statement. And here we see this as the deposit and amount n into self we change
self .balance (On screen). This is what a typical class statement will
look like it will have some init function at the top which constructs a new instance
of class by filling in its attributes. But then we have additional which might look up
data values or change them in this case we've changed the balance. And there's the withdraw
function because it's part of class we call withdraw method and it takes amount checks
to see it's not greater than balance and otherwise updates balance and returns it.
So these def statements create function obtains and names are bound as attributes of class.
So the class now has attribute deposit and attribute withdraw which are behaviors defined
for the class and therefore will be defined for all instances of the class.
So let's fill that in. Def deposit (self amount):
Self.balance + = amount. Before I did this so we will do the same thing
(On screen). If amount> self .balance:
Return 'insufficient funds'. Self.balance = amount.
Return self.balance.
Okay and we are done. So if you compare the top and bottom. You
see we are basically doing the same thing. Except for in this case we define the different
data attributes of an instance up in init function and then we can refer to all these
things via self throughout or methods. And we don't need things like I'm calling withdraw,
withdraw that's just built into the mechanism of the object system.
So that now if I create an account, I'll create my own this time because I don't even know
a person named Jim. I can deposit a hundred dollars in there.
I can withdraw 90 withdraw again and check my balance. Which looks similar to what we
did before with a dispatch dictionary except in this case we are using the object system
in a class statement.
STUDENT: You assign balance the 1 side so. .
JOHN DENERO: A.balance equals it's my lucky day.
So now I've clang it had balance of this account to be more than it was before and I can withdraw
from it. And go on a spending spree. Just from the outside whenever I have a reference
to this object I can refer the balance with dot depression and also do the same thing
within the body of the methods. So here I'm referring the balance of any object I look
at that I invoke the withdraw method.
STUDENT: The first argument when you define a method, is always going to be the object.
JOHN DENERO: Great question. What is all this self doing in terms of methods and how do
we make sure the first argument the every method is in fact the object we want to change?
That's again part of object system that's how methods work. Let's understand invoked
methods. Basically the ideas is that all methods we define should've access to the object its.
We should call it self. Be able to look up attributes and change THENL and thereby is
a bunch of different behaviors that all share the same local state.
So what does that mean? Here we have the deposit method. Its called with 2 arguments, evidentÊ
this is just a function every time it's called it's called with 2 things. Self is always
going to be an account instance. And amount is some number we pass in.
So it's takes has 2 formal parameters because it takes to arguments. But the dot notation
has a particular evaluation procedure which make sure the first argument is already supplied
correctly as the object of the dot expression. So when I say Tom's account is account Tom
and then Tom account.deposit hundred dollar the 2 arguments I pass in are the Tom account
itself. As self. And then I invoke this thing with
1 argument in order to fill in the additional slot.
The formal parameter amount is bound to hundred dollars. If I had 8 names, I would invoke
with 7 arguments. The first 1 is always filled in with the on the itself.
STUDENT: Do you call deposit with 2 parameters instead of dot notation.
JOHN DENERO: Can you call deposit just as function, yes.
STUDENT: What happens if you put this into environment diagram.
JOHN DENERO: Good question. We could do that but in fact the environment diagram system
supports I but I find it's not terribly helpful in terms of helping people to understand.
STUDENT: Are we having environment diagrams on the midterm.
JOHN DENERO: Is it on the exam! ? No. I'll ask you about the object system and how it
works but we won't mix into 1 question. That's a lot. So I think environment diagrams are
useful for local frames understanding how nonlocal frames work but with object system
it's easier the look at the code itself and not rely so much on the diagrams.
STUDENT: Is it possible to make attributes private or protected.
JOHN DENERO: Good question and sort of. Later.
Many of you have seen private protected from other programming languages it's not an issue
in Python not emphasize but think of it as: No, that doesn't exist.
Let me walk through more examples to see if I answer your question. The question is exactly
how the dot expressions work let's go through details in order to understand. So object
receives messages via dot notation and dot notation accesses attributes of either the
instance itself or the class. That's what makes them powerful. Is there
some procedure by which we look in the instance and then we look this the class. So dot expression
is some arbitrary expression something maybe complicated and then a dot and simple name.
The name has to be the name balance. We evaluate this by evaluating the expression
and then looking up name in the object that is the value of the expression. Now we need
to talk about what it means to look up a name in object. The important thing is that in
this dot expression, which is invoking the deposit method on Tom account. The way you
should break it up in your mind there's a dot expression which looks up the deposit
method and then we called it. And call expressions are called just like we have been calling
them throughout the course. This is a call expression with special operate,
which is a dot expression. How do we get at the attributes?
We can in addition to using dot expressions get them up by name. Where the name is a string.
Using the 2 built in functions get ator and has ator where AT&TR is short for attribute.
So in addition to saying Tom account balance use call expression notation which we know
can get anything in order to express that. Does Tom account has attribute deposit. Here
it does. So (On screen)they are ways of saying please look up a name.
And please return either an instance attribute associated with name or attribute of its class.
That's what ties together all different accounts to the account class itself. Is by looking
up attributes of the account sometimes you get the accounts attribute sometimes t the
instance particular instances attribute. Let's understand that.
There are 2 kind of things in Python, methods and functions. Python distinguishes between
them in the code as follows: Functions which we've created since the beginnings
of course versus bound methods. Which are the function bundled together with the object
that its being invoked upon. So the bound method is couple together a function
and the object on this that method will be invoked so think of object and function grouped
together like a tuple but it's not a tuple it's a bound method which is a built in type
in Python. Which you will get not by looking at the attribute of a class, that's just a
function, but by looking up the attribute of an instance. Tom account we got that when
creating a new can account. That Python will call a method. And the way you call a regular
function so account.deposit takes 2 arguments self and then the amount we pass in. And we
can call it look like a regular function like this it's an attribute of class account. But
if it happens to be we look up via an instance of class via a particular account then it
only takes 1 argument. Because this thing is a method.
Type of (On screen)it's a method it already had Tom account as first argument. Just pass
in the remaining argument, the amount itself. What have I done? I've said I have 2 kinds
of things: I have A which I created long ago by saying A is account John. And then I have
account itself. These are 2 different things. Account is object. It's an instance of this
class. What's the type of A? It's type is the account.
What is account? Well it is in fact the class. So account.deposit is a function.
It's the function deposit which I can call on A to add $12 to A's account.
What about A.deposit. That's different. That's a bound method.
That's already taken the deposit method that's part of the account and bundled it together
with the account A. So that I only have to pass in the additional argument, self is already
taken care of I have to just pass the account. And the effect of depositing $13 into the
account. This part is supposed to make programming easier. We are automatically supplying as
first argument the deposit, the account into which we want the deposit money.
Questions? Uh oh.
No questions! I've never been so clear in my life.
Okay. I'll move on if questions come to you let
me know. So what are the mechanics. Look up attribute
by name you start with expression on the left then dot is name. What do we do first? Evaluate
that expression to figure out what object we manipulate. Evaluate to the left of dot
which yields an object. Now we know the object of dot expression.
What about this name? The name could be part of the instance. So
it could be particular to the account that we happen to be looking at.
And so the first thing we do is check to see if name is matched against the instance attribute
of that object if attribute with that name exists, its value is returned as the value
of this dot expression. So the simple case when I Type A.balance, balance is instance
attribute I immediately get back the balance of that object. What if it's not there? Then
name is actually looked up in the class. That's why every object needs to know what its class
is. You need to be able to access the class attributes from the instance. The way that
works is that every account knows it's an account. And therefore, if it doesn't have
a particular instance attribute. We never said self.withdraw equals anything so there's
no withdraw instance attribute. But it is in the class.
Because we put it there in class statement. So then if we don't find the thing the instance
we look if class. Which yields a class attribute value.
STUDENT: If you make a bunch of copies or a bunch of instances of something does Python
make a bunch of copies of the functions? JOHN DENERO: So good question what happens
if I make 5 different accounts? How many different withdraw methods are there? So I make 1 account
class. But then I make a bunch of different accounts by calling account Jim, Jack, all
my friends star with J. I still actually only have 1 deposit method it's part of class.
So all different instances know they have the same class and therefore there's only
1 deposit function they all share together. The way it gets looked up is none of them
have withdraw instances, but they all have the same class which has this class attribute
value the withdraw method that actually does the withdrawing.
That's how we share behavior among different things of same type. They all have same class
looking up a name gets you stuff from the class. If class value you get back is returned
directly unless it's a function in which case the method binding happens. That means if
we found something in the class, and it's a function, then we fill in the self with
the object of dot expression that we valleyed in Step 1.
So we get bound method takes 1 less argument than original function because first argument
is filled in as object itself. That's the mechanics by which all different methods share
access to the same object. Is that self is filled in right here as part of looking up
attribute by name in a dot expression. Questions?
Let's look at example of when we find instance attribute versus class attribute.
Good idea. So A.balance is an instance attribute. How
do I know it's not obvious at all by just interacting and that's the point you are not
always supposed to know where you get it but just that you go got it of it's an instance
attribute because it was assigned to the instance init here. So anything that's created on this
level of indentation out here is class attributes so they are withdraw and deposit. But anything
that's assigned via attribute assignment statement that looks like this where self is on left
hand side and that is a new instance is an instance level attribute.
Let me just label that. And withdraw here is a class attribute.
And in fact, if I put some new name out here, like the interest rate, that would also be
a attribute. Instance attributes get introduced typically
by using self. And in the init although they can be introduced anywhere.
So that's instance attribute. So let's A equals account John now A has an interestÊ HmmÊ
perhaps I should save.
Now A has an interest that is a classes attribute so it didn't find it as part of instance how
do I know that well I can always look up actually it's a long story so ignore what I just did
too much for 301 that's the distinction here we have instance and is here classes and more
detail next time. Have a good day.