1
00:00:05,280 --> 00:00:10,309
We've learned a lot about Python dictionaries.
Now let's see how the documentation describes them.

2
00:00:10,309 --> 00:00:14,640
I'm going to go to a link, to
the python documentation on screen.

3
00:00:14,640 --> 00:00:20,240
As always, the link is in the resources section.
This is a more formal description of the dict type -

4
00:00:20,240 --> 00:00:26,781
and it looks scary! But don't worry - the more you
work with this documentation, the more sense it'll make.

5
00:00:26,781 --> 00:00:30,960
So starting from the top, the documentation
talks about Mapping Types, and notes that there's

6
00:00:30,960 --> 00:00:36,880
currently only one mapping type built into
Python. That's the dict type that we've been using.

7
00:00:36,880 --> 00:00:41,760
Those hashable values, in the first paragraph,
are the keys. The documentation tries to be very

8
00:00:41,760 --> 00:00:48,000
concise, and accurate. It talks about hashable
values, rather than keys, to document exactly

9
00:00:48,000 --> 00:00:54,800
what can be used as keys - and that'll make more
sense soon. It also mentions arbitrary objects. 

10
00:00:54,800 --> 00:01:00,480
It uses that phrase because you can store anything
in a dictionary. The keys must be hashable values,

11
00:01:00,480 --> 00:01:06,320
whatever they are, but the values we store in our
dictionaries can be any Python object. You can even

12
00:01:06,320 --> 00:01:12,330
store a dictionary or a list inside another
dictionary. The second paragraph says that 

13
00:01:12,330 --> 00:01:19,360
A dictionary's keys are almost arbitrary values. What
that means is, you can only use immutable objects

14
00:01:19,360 --> 00:01:25,600
as a key. It goes on to clarify that, saying
that mutable types may not be used as keys.

15
00:01:25,600 --> 00:01:31,280
ints and strings are immutable, and are commonly
used as dictionary keys. But if you need to, 

16
00:01:31,280 --> 00:01:37,520
you could use a tuple as a key. Let's click on one of
these hashable links and open it up in a new tab,

17
00:01:37,520 --> 00:01:41,840
to see what the documentation means by hashable.

18
00:01:41,840 --> 00:01:48,000
Once again, the text here is very concise and
precise. A hash value is a number that's calculated

19
00:01:48,000 --> 00:01:53,840
from an object's contents. For integers, the hash
value is the integer itself. For things like

20
00:01:53,840 --> 00:01:59,600
strings, a special function is used to calculate
the numerical hash value. We'll see why hashes are

21
00:01:59,600 --> 00:02:06,160
useful, and how a dictionary uses them, when we get
to the theory behind mappings. The third paragraph

22
00:02:06,160 --> 00:02:13,220
clarifies what it means for an object to be
hashable. Hashable objects must be immutable.

23
00:02:13,680 --> 00:02:18,720
But it does match some restrictions. We know
that tuples are immutable, so they could be

24
00:02:18,720 --> 00:02:25,186
used as a dictionary key. But if a tuple contains
a list, then it's no longer suitable as a key. 

25
00:02:25,186 --> 00:02:33,230
So a tuple can be used as a dictionary key, as long
as the items in the tuple are also immutable.

26
00:02:33,680 --> 00:02:37,840
Looking at this table, the left-hand column
shows some immutable objects that we can use

27
00:02:37,840 --> 00:02:44,400
as dictionary keys. The first item is a tuple
that only contains other immutable items.

28
00:02:44,400 --> 00:02:50,480
The tuple on the right hand side isn't suitable.
It contains a list, and the list could be mutated.

29
00:02:50,480 --> 00:02:56,000
Our code could add items to it, or delete them.
Because of that, we can't use this tuple as a

30
00:02:56,000 --> 00:03:01,600
dictionary key. Python won't attempt to create a
hash for a tuple that contains things like lists.

31
00:03:01,600 --> 00:03:08,006
You'll get a TypeError: unhashhable type if
you attempt to hash the tuple on the right.

32
00:03:08,720 --> 00:03:14,240
Alright, so let's go back to the
documentation about the dict mapping type.

33
00:03:14,240 --> 00:03:20,400
So the next bit of documentation - scroll down
a bit further - shows various ways to use the

34
00:03:20,400 --> 00:03:25,600
dict constructor. Now don't worry about what
a constructor is. For now, just treat it like

35
00:03:25,600 --> 00:03:30,240
another function. You've seen dict in the list of
Python built-in functions that we've looked at,

36
00:03:30,240 --> 00:03:36,800
a few times. If we scroll down a bit further, the
examples down here in this code block, all show

37
00:03:36,800 --> 00:03:43,760
different ways to create a dictionary with the
same keys and values; b uses a dict literal, and is

38
00:03:43,760 --> 00:03:48,880
the way that we've been creating our dictionaries
so far. The documentation example shows the code

39
00:03:48,880 --> 00:03:55,280
on a single line, but in our examples, we split our
literals over several lines. d and e show how to

40
00:03:55,280 --> 00:04:00,560
pass a list of tuples, or another dictionary, to
the dict function. You probably won't write code

41
00:04:00,560 --> 00:04:06,560
like the example for e, but you could pass b to the
dict function. That would create a new dictionary,

42
00:04:06,560 --> 00:04:12,320
with the same values as b. I'll skip the examples
that use keyword arguments - that's the lines that

43
00:04:12,320 --> 00:04:17,519
create a and f. We haven't covered keyword
arguments yet. If you remember, I said you'd

44
00:04:17,519 --> 00:04:22,160
need to know about dictionaries before you could
understand how keyword arguments work. But if

45
00:04:22,160 --> 00:04:27,120
you've guessed that keyword arguments are stored
in a dictionary, you're right. Below that, as we go

46
00:04:27,120 --> 00:04:32,320
through the remainder of the section, it describes
the operations that a dictionary supports. We've

47
00:04:32,320 --> 00:04:36,320
actually used a lot of these already, and I'm going
to discuss some of the others that aren't obvious.

48
00:04:36,320 --> 00:04:41,200
I don't think I need to explain what len
is, or scrolling down a little bit further,

49
00:04:41,200 --> 00:04:48,800
what clear is. Going back up here a little bit,
list and len are both Python built-in functions.

50
00:04:48,800 --> 00:04:53,520
That's why they appear before the alphabetical
list of operations and methods. If we scroll a

51
00:04:53,520 --> 00:05:00,080
little bit further, down here, there's some examples
of accessing items using a key, setting a value -

52
00:05:00,080 --> 00:05:05,680
again, using a key - and removing an item from the
dictionary. The documentation uses the letter d to

53
00:05:05,680 --> 00:05:10,800
represent a dictionary, in those examples. The
first function we haven't used so far, is iter.

54
00:05:10,800 --> 00:05:15,520
Using iterators, explicitly, is quite advanced.
You've been using an iterator every time you

55
00:05:15,520 --> 00:05:21,600
use a for loop. An iterator is created implicitly,
by the for statement. Later in the course, we'll see

56
00:05:21,600 --> 00:05:26,080
some examples of why you might want to create your
own iterator. But it's not something you need to do

57
00:05:26,080 --> 00:05:31,760
very often, and I won't discuss it just yet. Like
list and len, iter is a built-in function that can

58
00:05:31,760 --> 00:05:37,120
be used with any iterable or sequence type. It's
not specific to dictionaries - you can pass a list

59
00:05:37,120 --> 00:05:43,120
or a string to those three functions. We're getting
now, to the methods that we can use with a dict.

60
00:05:43,120 --> 00:05:47,564
Dot clear shouldn't need any explanation - it
clears all the items out of a dictionary.

61
00:05:47,564 --> 00:05:52,480
The copy method creates a copy of a dictionary.
That's fairly straightforward, but why does it

62
00:05:52,480 --> 00:05:57,280
mention a shallow copy? Do we get a dictionary
that's only interested in your looks? Or in how

63
00:05:57,280 --> 00:06:02,480
much you earn? Of course not. The difference
between a shallow copy and a deep copy is quite

64
00:06:02,480 --> 00:06:07,600
important, and we'll discuss that in the next
few videos. I'll also give some examples of

65
00:06:07,600 --> 00:06:14,640
some of the other methods that we haven't used
yet. I won't provide an example using popitem,

66
00:06:14,640 --> 00:06:19,440
because it's very similar to pop. Whereas pop
returns the value from the dictionary, popitem

67
00:06:19,440 --> 00:06:24,320
returns both the key and the value, as a tuple.
There are a couple of things to be aware of with

68
00:06:24,320 --> 00:06:30,480
popitem. The first is, you don't tell it which key
to remove - it automatically removes the last item

69
00:06:30,480 --> 00:06:39,760
that was added to the dictionary. That's what LIFO
means - it's an acronym meaning Last In, First Out.

70
00:06:39,760 --> 00:06:44,960
Imagine someone wearing bangles on their wrist. If
you put on a red bangle, a blue bangle and a green

71
00:06:44,960 --> 00:06:50,939
bangle, then they'll take them off in the opposite
order. The green bangle has to come off first - last on,

72
00:06:50,939 --> 00:06:56,000
first off. Another example would be a stack of
coins. The first coin you take off the stack would

73
00:06:56,000 --> 00:07:02,903
be the last one you put on it. In fact, a stack
is a very common data structure in programming.

74
00:07:04,160 --> 00:07:09,360
The opposite of LIFO is FIFO - First
In, First Out. that's like a queue at

75
00:07:09,360 --> 00:07:14,480
a bus stop. The first person to arrive at a
bus stop will be the first person to leave,

76
00:07:14,480 --> 00:07:19,926
when they get on the bus. We're assuming
a civilized behaviour here, of course.

77
00:07:20,800 --> 00:07:26,000
Another example of a FIFO queue would be putting
items away in your fridge. If you bought more

78
00:07:26,000 --> 00:07:31,360
milk, then you'd put the new bottle behind any
that were already in the fridge. When you take

79
00:07:31,360 --> 00:07:35,600
a bottle of milk out of the fridge, then you'd
be taking the first bottle that was put in. 

80
00:07:35,600 --> 00:07:41,661
If you don't do that, you could end up with a bottle
of milk that's been in the fridge for months. Yeuch!

81
00:07:42,000 --> 00:07:47,520
The other thing to watch out for with popitem,
is that you only get LIFO order with Python

82
00:07:47,520 --> 00:07:53,840
version 3.7 and higher. Python versions before
3.7 will return and remove random items from

83
00:07:53,840 --> 00:07:58,400
the dictionary. So pay careful attention
to notes like this in the documentation.

84
00:07:58,400 --> 00:08:03,440
If you write a program that relies on popping
the last inserted items, your code won't work

85
00:08:03,440 --> 00:08:08,720
on earlier versions of Python. Looking down a little
bit further, we've used the reversed function

86
00:08:08,720 --> 00:08:12,640
when working with lists, and it does the same
thing with a dictionary. It lets you iterate

87
00:08:12,640 --> 00:08:18,400
backwards over the dictionary. Now note that
it won't work with Python versions before 3.8.

88
00:08:18,400 --> 00:08:21,600
A requirement to iterate backwards
is that the keys are ordered,

89
00:08:21,600 --> 00:08:28,160
and that change was made in python 3.7. Python 3.8
could take advantage of that, to allow reversed to

90
00:08:28,160 --> 00:08:32,159
work with a dictionary. Alright, so I'll stop
the video here, and in the next one, we'll look

91
00:08:32,159 --> 00:08:37,840
at methods I've skipped over, and see some short
examples of each one. See you in the next video.

