Write Pythonic Code Like a Seasoned Developer Transcripts
Chapter: Classes and Objects
Lecture: Do not write get_thing() set_thing()
0:01 One of the primary reasons people will write non-Pythonic code
0:03 is they come from other languages that have other idioms
0:05 and they just move their code over and make them work
0:08 using the same former idioms and not really adopt the new Python ones.
0:11 So here we have some NotSoPythonicPet that we've been playing with,
0:14 it's got some private fields - age and name,
0:16 we'd like a way for us to get the name and get the age but not set it,
0:20 here we wrote a get_name and get_age, so that you can get those.
0:24 But this is not Pythonic at all, and when you use the code, it's not pretty,
0:28 it looks something like this, so here we create a NotSoPythonicPet,
0:31 it's going to be a cow called Betsy who is 4
0:33 and we can say she is named such and such
0:36 and is however many years old, so "cow.get_name", "cow.get_age".
0:41 It doesn't have to be this way, let's see how it should be.
0:45 All right, so here is the Betsy code again, not so Pythonic,
0:48 we are doing this and this, let's go down to this PetSnake type
0:51 that we are working with and do something different, do it better.
0:54 You should almost never write these getters and setters in Python,
0:57 instead, the much more natural way to work with this
1:00 would be to say "py.name", "py.age"
1:04 as if they were a field, now this can be just accessing underlined variables,
1:08 these could be computed like in a shopping cart you could say "cart.total"
1:12 and maybe that just actually does a loop and adds up all of the items,
1:15 but as a consumer, you don't want to think of these as functions,
1:19 you want to think of them as just attributes of the class, right?
1:23 So in Python, instead of writing those getters and setters,
1:26 we can say come over here and say I'd like to have a function called "name"
1:30 and this is going to return "self.__name", now if I try to run this code,
1:36 and let's do the same for age,
1:41 and if I come down here and I write this code,
1:42 we are going to get something entirely unexpected,
1:45 what do you get if you say the name of a function? Without parentheses,
1:48 you get the bound method, bound to this object.
1:53 That's not what we wanted, so then we have to say this, and that's not so pretty,
1:58 technically it works, but we are kind of back to the previous example
2:02 that was names for our getters,
2:05 so in Python we can use a decorator called a property decorator, from the built-ins,
2:09 down here I can say actually this is not a regular method but a property
2:13 and now if I say "py", well if I say it far enough down, "py. name and age"
2:18 you can see the little "p" by there, and if I access it like this,
2:22 this actually just calls the function, beautiful, right, don't write getters, write this.
2:26 Suppose I want to be able to change the age but not the name,
2:29 if we try to set the age, right now it's read-only, obviously,
2:33 and it says can't set the attribute we've already got this read-only property called age
2:38 but if we wanted to set the age, we can come down here and write another function
2:41 called "age", that takes the value and we'll say "self.__age = value".
2:48 Now we give it another attribute up here, we say "age.setter",
2:52 now this is less delightful than just add property but that's how it works.
2:57 So now we should be able to set the age and run it, first our snake is 6, then 7,
3:02 so just to make it clear, these are actual function calls,
3:04 not just changing the underline property, I'll do a print, there,
3:09 so all right, two little prints that every time you execute this code,
3:12 which could do anything we wanted to do, we just happen to be
3:15 setting the underlined private field,
3:17 it will print this and then when we get it will print that.
3:19 So here you can see, "Here is my pet snake", all we are getting is age,
3:22 its name and age and such and such, setting the age, getting the age and so on.
3:28 And finally like I said, you can have computed properties,
3:32 aren't really backed by underline store, so here I could say let's have "is_protected",
3:39 we could do return True or False depending on how high the protection level is
3:42 so we'll say, let's say "self.protected level value is greater than 5",
3:46 so if it's greater than 5, the snake is protected. if it's not then it's not, whatever that means.
3:51 so we'll just at the very end I'll print "py.is_protected"
3:55 you can see this property read-only property, run that, no, the snake is not protected.
4:01 All right, so this is not based on just returning something,
4:03 we can compute whatever we want to.
4:05 Properties are really useful, very Pythonic
4:07 and I recommend that you make good use of them.
4:10 So let's see in a graphic how we evolve this, right, getter/setter - bad idea.
4:14 In our Pythonic pet, our PetSnake, we've got our age and name
4:19 and here we are writing a property that says get me the read only version of the name
4:23 and the read only version of the age.
4:25 We also saw we can make writers or setters for the properties,
4:29 as well as computed properties that are not just returning underlined fields.
4:33 So with this in place, we can write as a consumer of the class,
4:36 much more natural code.
4:38 If we create a pet, it's called "py"
4:40 and its name is "py.name" and its age is "py.age".