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