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