Write Pythonic Code Like a Seasoned Developer Transcripts
Chapter: Classes and Objects
Lecture: Defining fields on classes
Login or
purchase this course
to watch this video and the rest of the course contents.
0:01
Let's talk about the Python idioms on classes and objects. And let's start in the construction of classes, how do you build them up,
0:08
how do you add fields and to a lesser degree when we get farther along, methods. So here I have a class defined called NotSoPythonicPet.
0:17
And we are going to do several non-Pythonic things to it but let's start up by giving this pet a way to set a name and to set an age
0:24
so that we can ask it, hey pet, what is your name, what is your age. So we can come over here and this is very non-Pythonic
0:31
so don't do this, we can come over here and we can say "set_name" and give it a name here, and say "self.name = name".
0:39
OK, that's great and we could do the same thing for age so now we can set the name and we can set the age.
0:50
Now, there is nothing technically wrong with this code, we shouldn't do this but technically it's not wrong,
0:55
these are just warnings saying "don't do" what we are doing here because it's not Pythonic, OK, so but we can come over here and say "cow.set_name()"
1:03
and let's call it Betsy, and we could set its age and how old is this cow, 7.
1:11
OK, so let's run this, make sure everything hangs together, we have a pet. Now this little string over right here,
1:18
this is not the best description of our not-so-Pythonic cow, because we could say "hey, this is a pet, it's name is Betsy, it's age is 7",
1:27
so why don't we do that. So a pet whose name is {} and age is {}. So now we have pet whose name is whatever the name is
1:41
and the age is whatever the age is, so let's try this. Great we have a pet whose name is Betsy and age is 7.
1:48
Now, technically, you can set fields on these types anywhere you want, within them,
1:54
out here, I can also say "cow.happiness = 11", it's a very happy cow, probably one from those California milk commercials,
2:04
and we could even incorporate the happiness up here and run it, and great, it's happy. What's wrong with this? Obviously, we should not be doing this.
2:14
Why? Because, what if we forget to set the name for example, bam. Sorry, this pet has no attribute called name, that's unfortunate, isn't it.
2:27
And even if we called all the methods, how are you suppose to know that you've got to do this, right?
2:31
This is really a terrible way to create classes, let's go over here and turn, we'll get rid of all of these, we'll just comment those out.
2:40
Forget this happiness bit for a minute, that was just playing around, OK,
2:44
so how should we do it? Of course, we probably want to pass this to the initializer, if we did want to have the ability to set a name and set an age,
2:52
we could leave this here and say "self.name = None", and "age = None", or maybe "age = 0", as it's unset, something like this.
3:05
So run, that doesn't give us a great answer, but at least in the __init__ we know all the moving parts of our class, of our type.
3:13
So, this is not, well, this type has a name field, if and only if you happen to call this other method but before that it doesn't, right,
3:22
this is a terrible way to write code, so don't do this. And if you feel you must do something like this, at least initialize these to somewhere empty.
3:30
But I am going to go ahead and say "let's not do this", let's instead... I'll leave this commented out for you, for the code you download,
3:37
let's instead say "you have to supply a name and age to create this class", to create an object of this class,
3:43
and we come down here to say "self.name = name" or in PyCharm you just hit Alt+Enter,
3:48
and it will do that for you, and Alt+Enter and it will do that for you, and it does it of course, the way we are recommending.
3:57
But now, we've got to supply a name and an age or it's going to crash as you can see, and Betsy's back.
4:06
Let me show you one other way of adding fields to a class that works really well and is very common.
4:12
So remember, in our slicing example we were over here doing this query against this measurement type,
4:17
let's look at that measurement class, for a minute. This is a SQLAlchemy ORM-based class and it's mapped into our database, via SQLAlchemy,
4:26
so basically there is a measurement table, corresponds to this class, now notice, here we are not using the __init__
4:34
we are actually defining the type by adding these class level fields, so we've got id, x, y and value,
4:41
over here, notice we can say things like "cow.name" and that works fine, it runs fine, but we can't say NotSoPythonicPet.name
4:53
Now, PyCharm finds it here but it probably shouldn't because if you run it, this type has no name, obviously. This is an instance level property,
5:03
you can think that this is kind of a static level type of thing, as a static field from other languages if you will,
5:09
so over here, if we write it like this, we get to write code like this, so here is how we actually wrote our query to do this,
5:16
I want to create a "query(Measurement)", "filtering(Measurement.value > .9)", order_by(measurement.value.desc()), things like that.
5:24
OK, so this is another very common way to define fields of our class that I think is Pythonic,
5:31
if you want them to be type level, if you want them to be only instance level, this is the way to do it. Here we have our NotSoPythonicPet,
5:41
and it's doing a couple of things right and a couple of things wrong.
5:44
First of all it has a "self.age = age", "self.name = name", in the __init__, that's good, but when we call "get_name" it happens to set another field,
5:54
another attribute that only exists after you call "get_name" that turns out to be a really bad idea.
6:00
And we can get the age back by saying "object.get_age" we should define our fields only in the __init__ or in the more static style
6:07
that I showed you, a SQLAlchemy, and we should never create new fields outside of __init__ based on some behavior that makes it very hard
6:15
to understand if and when those fields will be there.