Python Memory Management and Tips Transcripts
Chapter: Efficient data structures
Lecture: checking friends in the friend map
0:00 Alright, well, let's actually implement this "is_friend" thing.
0:03 So we actually want exactly the same tests here.
0:10 So, if there's no person or no friend,
0:12 there can't be a relationship between them,
0:14 so we'll say "return False".
0:16 If it's the same person, it's you,
0:20 Let's say True, False, I don't know.
0:22 Are you a friend of yourself or not?
0:24 You can decide what the right metaphysical or philosophical answer is right there.
0:31 But what we want to do is we actually want to say,
0:33 "give us the friends of this person" and this is actually going to be a list.
0:40 It's gonna come out like so,
0:43 but not any old list. In fact,
0:46 this is going to be a list of "weakref".
0:50 So that's what we're storing. That's what we put in over here.
0:52 So when we get it back,
0:53 it's a list of weak references.
0:55 These will not actually keep those friends alive,
0:58 but we will be able to get them back if we need it.
1:02 So we'll say something like this "for f in friends",
1:07 like so, if I say f or ref,
1:10 this is gonna be, we'll call it a reference, I don't know. A little bit complicated. This is a
1:14 weak reference to the friend, not the friend themselves.
1:17 If we can get a hold of them,
1:19 we'll do it like this, we'll say,
1:21 F is this And we'll say,
1:22 "if there's a reference, gotta check that first, and that the id.." say this
1:28 is a person, so we get auto complete here.
1:31 So "this is an id which is equal to the friend.id".
1:35 So the friend we're asking about
1:37 is in the list of friends because it was added here.
1:42 It's still around, right here. It's not cleaned up,
1:45 so it still exists in the system,
1:47 and it's actually the same person, right?
1:50 So we're basically going through all the people, return True,
1:53 return False. All right, there we go.
1:56 Let's see if I got this right.
2:00 First we want to create cycles.
2:01 Yes. Is Michael a friend of Sarah?
2:03 Oh, yes. Is Michael a friend
2:05 of Zoe? No, they're not,
2:06 they're not together. How cool is that?
2:11 Pretty interesting. What we'll see is that these are not actually keeping those objects around,
2:16 or this actually is not keeping around over there if we clean them up.
2:20 Okay, so this is interesting.
2:22 you might think. Well, "okay,
2:23 Michael, this is way overkill with this weak reference thing because we're just saying True
2:28 or False, all you have to store is the id of the friend and the
2:31 id of the person and you're good".
2:33 Yes, but in the previous example,
2:35 I could actually get the friends. I could say
2:37 "here is my list of friends for this person" check this out.
2:42 So we can still do that without keeping these references, or these cycles, around.
2:45 So we can say "get friends of person" and it's going to return a concrete list of
2:54 person. So, these are gonna be real people,
2:57 not weak reference type things. We'll say "friends is a
3:00 list of weakref, just like before, equals map of person.id"
3:08 and we have our cool default list working for us here as well.
3:12 Now watch this. We're gonna say, we're going to return,
3:16 Let's just make it a little more explicit, let's say "realized friends is
3:23 going to be p for ref in friends".
3:29 Now, what we need to do is we need to check that calling
3:33 this is not empty, but we can't do it directly here, we might want to
3:37 return that. So we're gonna use what's called the "walrus operator".
3:41 You can skip that and just ref()
3:44 this if you have an older version of Python, older than 3.8, but what we're
3:48 gonna say is "if P := ref()" like this. So what's happening is we're in
3:57 our test we're actually trying to realize the variable p here.
4:02 If it comes back and it exists,
4:04 it's not cleaned up yet. It was in the friends list,
4:06 and it's still around, then we're gonna actually hang on to that.
4:09 So we don't have to call that check twice.
4:11 We'll just return a realized friends.
4:17 Okay, let's just print out here really quick.
4:27 p1. Let's say yes.
4:31 Here we go, look at this.
4:32 We have our p1 and I guess we wanted to print this out.
4:37 We could even do a little "p.name for in that" to just see who
4:42 the names are. So Sarah is a friend of Michael.
4:46 Look, we got it back.
4:48 And yet, no cycles that were actually created in memory.
4:52 How cool is that? I'm pretty happy with the way this works. Now,
4:57 there could be one thing that you might want to do. We could have set
5:01 up these friend relationships by adding friends.
5:04 I'm going to say we have improved it so I'll drop that.
5:07 We could have set this up and then we could be done with people.
5:10 Now, because we're storing everything as weak references,
5:14 it's probably okay, but what's gonna happen is there will be maybe,
5:19 like, these lingering data structures that we're going to go over, we'll
5:22 test them and they we'll throw them away,
5:23 Right? So when we say
5:25 "is this person a friend?" let me be specific here.
5:29 Like when we're going through and trying to find a friend,
5:31 we loop over all of them and we try to check for them right here and
5:35 test it there. There's gonna be some scruff that builds up. So we could write
5:40 one more function and, let me just throw it out here just because it's not super important
5:45 for this, like a kind of a cleanup thing.
5:48 But we could go write an "erase_person" function and it says "okay if that
5:52 person has not been removed from the map,
5:56 go ahead and remove them from the map and then go through all of the friends
5:59 and if that person is a friend,
6:02 you know, remove their weak reference"
6:03 Basically. So that's kind of a
6:05 long and dragged out thing. I think it might be necessary in some use cases
6:11 and not others, right? As we saw already,
6:13 because everything is a weak reference,
6:14 we're not actually creating cycles or keeping things alive.
6:18 But this map here could get unwieldy,
6:21 in which case you might want to write some code like that and call it when
6:24 you know you're done with certain people.
6:27 Alright that's it. Cool.
6:28 Now, I do not want you to think that I believe this is the
6:32 absolute best way to solve this problem.
6:35 There are many ways to solve this problem,
6:37 and I just want to show you something that's completely different from the default.
6:42 What we're gonna do is we're gonna have a person object.
6:45 They're gonna have a list of friends,
6:47 and we're gonna go over here and we have to create this direct relationship.
6:53 Instead, we can go use things like, funky things like weak references and other data
6:59 structures to try to create those relationships and hold those connections,
7:03 and if either of them happen to go away,
7:05 well, obviously that connection got broken as well.
7:08 And you just say "no,
7:09 they're not friends" or "no, they're not related".
7:11 But we can always re-acquire the elements like we are down here for the things
7:18 that are not cleaned up. So I think this is pretty interesting,
7:21 and I wanted to put it out here as something to give you a thing to think
7:26 about. Something to give you an example for how you might approach a problem like
7:30 this that is sort of non-standard but potentially could be more garbage collector friendly.