Python Memory Management and Tips Transcripts
Chapter: Efficient data structures
Lecture: checking friends in the friend map
Login or
purchase this course
to watch this video and the rest of the course contents.
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.