Write Pythonic Code Like a Seasoned Developer Transcripts
Lecture: Safer dictionary item access
0:01 One of the most common actions that we perform at dictionaries is
0:03 to read values from them and see what they are storing.
0:06 So let's look at the variety of ways we can do this in Python.
0:09 Here we have a dictionary about a movie,
0:11 information about how long it was, what its title was,
0:14 when it was made, things like that.
0:15 We are going to go and access things like what was the title,
0:18 or what was the year and see how we do that.
0:21 So let's go over here and try what I am going to call the optimistic style,
0:25 so we might want to print out the year,
0:27 so we can come here and I can just say (data [ 'year' ])
0:33 and we should get back this,
0:35 and let's go ahead and make that a number while we are at it.
0:37 So, if I run this you should see at the top 2001,
0:41 that works great if the value is in there,
0:43 but if I ask for something like the rating,
0:45 and there is no rating for this movie, not so good.
0:48 so we get key error rating.
0:51 So let's comment that out, so that we can get to the rest of our app.
0:54 So you might say well, that didn't work out so well for me,
0:56 let's be a little more careful, pessimistic,
1:00 let's assume it's going to not work and put a lot of error handling around it,
1:03 so we could print, we could do basically the same thing here,
1:07 we could print out the year, we could print out the rating,
1:09 and we could catch the error and just print it out like this.
1:17 Notice the PyCharm thinks oops, it's misspelled,
1:19 it should be oops apparently.
1:22 All right, so let's try this, awesome, so we see optimistic style 2001
1:27 and if we try to do this remember,
1:30 it crushes because our optimism was misplaced,
1:32 so down here we again,
1:34 we get the year and instead of crushing we actually catch the exception,
1:36 we say oh there is a key error rating.
1:39 All right, so that's one way we can do it,
1:41 this makes it pretty hard though, there is a lot of times
1:44 when you want to create concise little expressions,
1:47 and you want to use the values that come out of these dictionaries,
1:50 like a list comprehension or something like that,
1:53 especially on data science, these are very common
1:56 and this format just entirely breaks this fluent expression functional flow,
2:01 so we can do other things instead,
2:04 now if we want to know for sure whether an item is in the dictionary
2:06 we can just ask first so we could say if year is in data then we'll print data of year.
2:15 Similarly, same thing for rating, and it's not just so we can
2:21 detect it in this case let's print out, oh, we didn't find the rating,
2:25 all right, let's run and see how that works.
2:28 Ok, safety first, we checked yes,
2:32 it was true that year was in there so we want its value printed out,
2:36 we asked if rating was in there, no it wasn't
2:38 and so oh we didn't find the rating, is what we found out here.
2:41 Now this safety first style here lets us check first
2:45 and then use the data if we are willing to just say look,
2:49 I am willing to accept none or sort of a missing value
2:52 we can use a different style and I actually like this style,
2:55 I have started to use it more and more
2:57 because it lets me test a variety of things all at once.
3:00 So down here I can say instead of data bracket where I index in
3:03 and of course of the values missing I get a key error, I can say get,
3:06 and notice it has a key and a default.
3:09 So if we come in here, we can say the key is going to be
3:12 again year and the default is none, so if there is no year, fine just give us none.
3:17 Same thing for rating, so let's run this again.
3:20 Like before, we got the year but now instead of a crash,
3:23 we have some kind of a exception handling or if else block,
3:27 we just get none and that's actually often quite useful.
3:31 So, sometimes none is not what we want.
3:34 So this style up here works well if we are willing to accept none
3:37 but here we have a year and that's supposed to be a number,
3:40 what if we would like to have say zero or negative one or something like that
3:43 for the year if it doesn't exist, we could use our if/else block
3:47 or something like that but actually we can just come down here
3:50 and say let's get zero if the year isn't there and for the rating,
3:54 let's suppose we are just going to get a one star,
3:57 or maybe an empty string or something like that, we'll go with one star for now.
4:00 Or maybe so it doesn't look so bad we'll say 3 out of 5 stars, something like that,
4:05 so if we don't specify rating we'll get this.
4:08 this is a little bit contrived, but at least you'll see how it works.
4:12 And we explicitly ask for it but supply an alternative,
4:14 we get 2001 because of course the year is there,
4:17 but the rating which is missing just gives us
4:19 what we would assume to be the default unrated value we'll say that's 3 stars,
4:23 we could maybe make that empty, or who knows.
4:26 This style is really nice, however, it requires that we specify
4:29 the alternative every single time we call get
4:31 what if we would like whenever somebody uses our dictionary a different default,
4:36 so there is a thing in collections called default dict,
4:40 we can import that up at the top and down here we'll have data,
4:45 we'll just sort of replace data with this default dict,
4:49 so we need to give it a couple of things,
4:52 one thing we have to give it a callable that will return the default value,
4:56 not the default value itself but a thing that will create the default value,
4:59 so we can use a lambda, and we can say
5:02 when somebody needs to create a default value,
5:05 let's say missing, so here it looks little funky maybe to you,
5:07 but this is the function and when you call it it returns the value missing.
5:12 Next, let's make sure that we copy the existing data into this dictionary
5:16 and then we'll place it with this default version of itself,
5:19 let's just print out data to make sure that that's sort of transformation worked.
5:23 All right, here is the default dict with the lambda function,
5:26 and the data we expect, beautiful.
5:28 So let's try this exact same thing again but avoid supplying any of the values there,
5:34 if I would run it, we'd expect the year to come out as 2001 as it has every time,
5:38 and we would expect rating to require whatever the missing value is
5:43 so it should say missing.
5:46 All right, I always make this mistake, even on default dicts,
5:49 when you call get, you are still going to get the default value
5:52 which is the default parameter set to none,
5:55 the default dict behavior comes in, when you access it like this,
5:59 I almost edited that out but it seems like I make that mistake often
6:01 and you may make it as well so hopefully it's helpful to see it.
6:05 There we go, year is 2001, and instead of crushing, we get missing for rating.
6:12 All right, so that gives you the spectrum of ways to access data from dictionaries,
6:16 Pythonically in a safe way and you saw that Python gives you many options
6:20 to control the spectrum of the behavior you want,
6:23 do you want to make sure it crushes right away if you try to get a value it's missing,
6:26 fine you can do that, do you want to always supply default value,
6:29 you can do that, and so on.
6:31 So, we started out with this dictionary,
6:33 and we said let's just try to get the year and rating from it like so,
6:36 year was totally fine, but rating, not so fine, remember we got the crash,
6:41 key error rating, we said ok, well let's try it this way,
6:43 let's use .get and we'd like to specify an alternative value
6:47 so for year we said the alternative value is going to be zero, and then in this case,
6:52 we are going to say if you have no rating, please provide negative one.
6:56 And you can see, because there was a year we got the value,
6:58 there is no rating, we got -1.
7:00 This kind of default is really helpful because then
7:02 if you know you are going to parse that to an integer, or number,
7:05 something like that, you can provide a default
7:07 that's always going to parse rather than none.
7:09 Finally, if we want to set this behavior universally across a given dictionary,
7:13 we can use default dict from the collections module,
7:16 we specify a function that will return the value when called
7:20 and here we are passing in the original data to sort of transform
7:23 the basic dictionary into a default dict, dictionary.
7:27 Now when we access data out of our dictionary,
7:29 we ask for year, we get the year value because it's there.
7:33 If we ask for rating which is not in there
7:35 it's going to call our lambda to supply the default value,
7:38 that will return missing.