Write Pythonic Code Like a Seasoned Developer Transcripts
Chapter: Classes and Objects
Lecture: Encapsulation and data hiding

Login or purchase this course to watch this video and the rest of the course contents.
0:01 Encapsulation and data hiding is a key building block for object-oriented design. And Python, being a very object-oriented language,
0:07 or at least having great support for object-oriented programming, of course, has ways to do this.
0:13 But I would say it's less Pythonic to focus heavily on these ideas,
0:16 things like private variables, and whatnot with inside classes or protected variables that only derived classes can see, things like this.
0:25 But let's look at it anyway. So, over here we have a class called PetSnake, and you can give it a name and you can give it an age,
0:31 and you can supply this protected value but it builds it up as you create it and possibly these changes over time, right,
0:38 this is a great simplification of anything you might really use. And, like before, we have this string overwrite,
0:43 where we can print out some information about this. So here we can say "Here is my pet snake:", I want her called Slide, it's 6 years old,
0:50 and we can just print it out, that will call this method, we can also access its values directly here, so let's just run this.
0:57 Great, here is my pet snake, age 6, looks like it has an age and a name backwards but that's fine, and the protection level here, perfect.
1:04 There is nothing wrong with this class, it seems fine to me, but what if we wanted the age and the name to be read-only?
1:11 Once you have created a snake, you can't change its name, once you've created a snake, you can't change its age,
1:16 other than possibly having some way to like give it a birthday or something like that.
1:20 First of all, let me switch these, because this is kind of bugging me, this is backwards,
1:24 so in Python, there is a way to do this and let's work with this protected value,
1:29 let's suppose that we would like this to be accessible to derive classes but we want to indicate to the consumers of it,
1:35 "hey you probably shouldn't be messing with it", so let's just, before we change it, let's print it out over here,
1:40 so here we'll print it out and see everything is fine, if you look at the warnings form PyCharm, no warnings.
1:45 So the way that you indicate something should not be consumed outside of the class or more generally outside modules,
1:51 sort of externally is to say "_" as the prefix. So now if I say this, notice, this goes away,
1:57 obviously, because it doesn't exist, but we can put it back, that's fine, this goes away because it doesn't exist, we can put it back,
2:04 but now we have this warning and PyCharm is saying: "Access to a protected member such and such of class
2:10 you probably shouldn't be doing this unless you know what you are doing." However, this is just a warning, it still works.
2:17 Notice here we are reading the name and the age but we just as well could, and we are going to say "py.name = py.name.upper()", something like that,
2:27 so now we have Slide, so we are actually changing the type, OK and maybe I'll change this print statement order as well
2:33 here we go, SLIDE and SLIDE, capital. So what if we don't want this to be possible, we want read-only access to this and we'd have to provide a way
2:40 to get to it which, we'll get to later. So the way you do that in Python is you use double underscores, and of course down here,
2:48 those names changed, let me put this back for just a second, if we really want to make this change we can hit Ctrl+T
2:54 and do double underscore and change it everywhere Ctrl+T to save me some typing and be safer, of course.
3:01 You can see it changes everywhere but down here PyCharm is like "not so sure this is going to work well for you",
3:06 unresolved reference, well, maybe it's just hiding from us, maybe it's saying you know, you really shouldn't access this,
3:12 we are going to tell you that it's not there. If I say "py." and the only reason it thinks the name is there is because we are doing this line,
3:18 if I take this line away, there is no name, and it thought that line was creating the thing called __name which it would have,
3:24 if we set it, you can see those don't show up. OK, so now let's run it and see what happens. Boom, PetSnake has no thing called __name
3:34 and yet if I hide this, it does seem to have __name, so what is going on here? So you really can't access it by name here,
3:43 so let's look, so we'll look inside of type and say "what methods and fields does it have?" with this thing called dir, so I can "dir(py)"
3:51 and ask: "What basically features do you have?" It'll show us all the various things here,
3:57 so if we come over and we look for, here is our protected value, let's go and add just one normal value,
4:04 so I'll just say "self.normal = True", so here at the end is our normal value,
4:09 here is our protected one so we can't get to it, we are just told "you probably shouldn't".
4:13 So here we are saying "self.__age", "self.__name" and that seems to work,
4:18 but it's actually got this rewritten name, where it's rewritten based on the type.
4:24 So technically, you could come over here and copy this out and access this, and it certainly wouldn't look like what's written up here
4:31 and it would tell you "you know, you probably should stay away from that." This is how you do private fields within classes in Python,
4:37 here is how you do protected ones. And of course, doing neither of those, makes it just a normal type. OK, so here is our PetSnake in a graphic.
4:46 We saw if we wanted the age and the name to be completely private, we use double underscores,
4:52 if we want to have a protected variable that we want to strongly encourage people
4:55 to stay away from, we use single underscores and you saw that we get warnings on the linters and things like that,
5:01 so if we go and write some code that tries to access this type, here we can see we are creating a PetSnake called a py
5:07 we'll get to this property thing in a moment, if we want to say "py._protected", we can, but that does give us a warning, if we try to say "py.__age",
5:19 we saw that it crashes and basically that name doesn't exist, it's technically rewritten to be kind of hidden but normal access doesn't work for it.

Talk Python's Mastodon Michael Kennedy's Mastodon