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