1
00:00:04,730 --> 00:00:07,910
When dealing with data in tuples, you can

2
00:00:07,910 --> 00:00:09,410
make the code more readable by

3
00:00:09,410 --> 00:00:12,469
using named tuples. In this video, we're going

4
00:00:12,469 --> 00:00:13,490
to have a quick look at these named

5
00:00:13,490 --> 00:00:15,590
tuples, what they are and also how

6
00:00:15,590 --> 00:00:17,779
to create them. Now there's some good

7
00:00:17,779 --> 00:00:19,340
documentation, if we swing over to the

8
00:00:19,340 --> 00:00:22,730
Python website. We've got

9
00:00:22,730 --> 00:00:24,440
some information here relating to named

10
00:00:24,440 --> 00:00:28,130
tuples, and this will be a good thing

11
00:00:28,130 --> 00:00:29,689
for you to read because it does explain

12
00:00:29,689 --> 00:00:31,609
them well, so I suggest you check that out

13
00:00:31,609 --> 00:00:33,769
after you've been through this video.

14
00:00:33,769 --> 00:00:34,940
One thing I would like to point out,

15
00:00:34,940 --> 00:00:37,550
though, is that just before the change history

16
00:00:37,550 --> 00:00:39,620
in example down here, this comment here,

17
00:00:39,620 --> 00:00:41,210
and it talks about the fact that named

18
00:00:41,210 --> 00:00:43,699
tuples are lightweight and require no

19
00:00:43,699 --> 00:00:45,769
more memory than regular tuples. And that

20
00:00:45,769 --> 00:00:47,330
is certainly true. They do need a bit

21
00:00:47,330 --> 00:00:50,479
more work to create, but not a lot.

22
00:00:50,479 --> 00:00:52,489
So let's see how to use them in a

23
00:00:52,489 --> 00:00:54,620
Python program. So you should have downloaded

24
00:00:54,620 --> 00:00:56,659
data.py from the resources

25
00:00:56,659 --> 00:00:58,790
section of the last video. So go ahead and

26
00:00:58,790 --> 00:01:00,309
grab that if you haven't got that already,

27
00:01:00,309 --> 00:01:03,920
and we'll go back to finder, in my case

28
00:01:03,920 --> 00:01:06,560
on a Mac.  We'll go to Windows Explorer

29
00:01:06,560 --> 00:01:07,880
if you're on a Windows machine. Take a copy

30
00:01:07,880 --> 00:01:10,759
of that downloaded file, swing back

31
00:01:10,759 --> 00:01:12,740
to IntelliJ and we're going to right

32
00:01:12,740 --> 00:01:16,579
click and paste to bring that file into

33
00:01:16,579 --> 00:01:19,670
Python. And in this video, we're going

34
00:01:19,670 --> 00:01:23,539
to be using plant based tuples, named tuples.

35
00:01:23,539 --> 00:01:25,340
You can see examples of those on

36
00:01:25,340 --> 00:01:27,799
lines 15 and 16, but there is also

37
00:01:27,799 --> 00:01:29,960
a people list at the start there, on line 3.

38
00:01:29,960 --> 00:01:31,719
We'll be using that in the next video.

39
00:01:31,719 --> 00:01:34,820
So how do we actually use named

40
00:01:34,820 --> 00:01:36,950
tuples? Well firstly, as you can see,

41
00:01:36,950 --> 00:01:39,590
on line 1 here in our data.py, we're

42
00:01:39,590 --> 00:01:41,149
importing named tuple from the

43
00:01:41,149 --> 00:01:43,310
collections module. So that lets us

44
00:01:43,310 --> 00:01:44,960
create named tuples, as you've

45
00:01:44,960 --> 00:01:45,590
probably guessed.

46
00:01:45,590 --> 00:01:48,920
Now before creating a named tuple, we have

47
00:01:48,920 --> 00:01:51,020
to define what the names are, and again

48
00:01:51,020 --> 00:01:53,390
you can see in lines 15 and 16

49
00:01:53,390 --> 00:01:56,359
we've defined two named tuples; plant and plant

50
00:01:56,359 --> 00:01:59,420
details. The first argument to named tuple

51
00:01:59,420 --> 00:02:02,539
is the type name as a string. I can't see

52
00:02:02,539 --> 00:02:03,920
any reason to make that different to the

53
00:02:03,920 --> 00:02:06,350
name that we assign the result to, but

54
00:02:06,350 --> 00:02:07,159
you can if you want,

55
00:02:07,159 --> 00:02:09,800
if causing confusion is your thing.

56
00:02:09,800 --> 00:02:12,500
So I'll change the first plant on line 15

57
00:02:12,500 --> 00:02:17,030
to P, and if we scroll down and have a

58
00:02:17,030 --> 00:02:17,920
look,

59
00:02:17,920 --> 00:02:20,170
notice on line 42 down here, we've now

60
00:02:20,170 --> 00:02:22,180
got errors where I've used plant, and

61
00:02:22,180 --> 00:02:24,700
that confirms it's the returned object

62
00:02:24,700 --> 00:02:27,160
that we need to use when creating our

63
00:02:27,160 --> 00:02:29,530
named tuples. Because if you go back now

64
00:02:29,530 --> 00:02:31,540
to line 15 again, if we undo that change,

65
00:02:31,540 --> 00:02:36,130
and instead change the second plant to P,

66
00:02:36,130 --> 00:02:40,680
this one here, let's scroll down and have a look,

67
00:02:40,680 --> 00:02:43,690
we're not getting any errors. So you can

68
00:02:43,690 --> 00:02:45,070
do that, you can make them different if

69
00:02:45,070 --> 00:02:45,520
you want,

70
00:02:45,520 --> 00:02:47,650
again if causing confusion is your thing,

71
00:02:47,650 --> 00:02:49,090
I suggest you go ahead and do that, but

72
00:02:49,090 --> 00:02:52,030
seriously, I can't see any reason to make

73
00:02:52,030 --> 00:02:53,380
those different. So generally, they'll be

74
00:02:53,380 --> 00:02:55,090
the same. So what we've done here then,

75
00:02:55,090 --> 00:02:57,550
on line 15, we've created the new name

76
00:02:57,550 --> 00:03:01,480
tuple using plant but their type is P.

77
00:03:01,480 --> 00:03:03,519
Now to see why that's confusing,

78
00:03:03,519 --> 00:03:05,890
I won't undo that change just yet.

79
00:03:05,890 --> 00:03:07,900
What we'll do is create a new Python file

80
00:03:07,900 --> 00:03:11,709
in the project, and we call this one named

81
00:03:11,709 --> 00:03:21,100
tupletest, and we'll go ahead and type

82
00:03:21,100 --> 00:03:23,940
some code in here; so line one, from data

83
00:03:23,940 --> 00:03:27,760
import basic_plants underscore

84
00:03:27,760 --> 00:03:31,600
list, comma then plants_list.

85
00:03:31,600 --> 00:03:32,799
On line three, we're gonna type

86
00:03:32,799 --> 00:03:36,370
print parentheses plants underscore list left

87
00:03:36,370 --> 00:03:37,780
square bracket zero right square

88
00:03:37,780 --> 00:03:40,180
bracket, then closing parentheses. So I put the

89
00:03:40,180 --> 00:03:42,160
data in data.py to save having

90
00:03:42,160 --> 00:03:44,440
to type it in again, and also so that we

91
00:03:44,440 --> 00:03:46,299
could reuse it in different example

92
00:03:46,299 --> 00:03:48,730
programs. So the code, as you can see, we

93
00:03:48,730 --> 00:03:50,130
start by importing the two tuples,

94
00:03:50,130 --> 00:03:52,120
basic_plants underscore

95
00:03:52,120 --> 00:03:53,920
list is a list of ordinary tuples,

96
00:03:53,920 --> 00:03:55,959
and plant_list is a list of

97
00:03:55,959 --> 00:04:02,790
named tuples. So if we run the program,

98
00:04:02,790 --> 00:04:05,560
you can see down the bottom, it shows the

99
00:04:05,560 --> 00:04:08,440
first item as being of type P.

100
00:04:08,440 --> 00:04:10,660
So everything works.  It's just confusing to

101
00:04:10,660 --> 00:04:13,269
create something of type P when we use

102
00:04:13,269 --> 00:04:16,029
plant to create it.  So don't do it

103
00:04:16,029 --> 00:04:17,620
unless you've got a really good reason to do so.

104
00:04:17,620 --> 00:04:20,440
I'm gonna switch back to data.py

105
00:04:20,440 --> 00:04:22,919
and I'm just going to undo that change now. OK.

106
00:04:22,919 --> 00:04:25,960
Alright, so that was the first

107
00:04:25,960 --> 00:04:28,210
argument. Now the second argument is

108
00:04:28,210 --> 00:04:30,640
just a list of the names we want to use for

109
00:04:30,640 --> 00:04:31,720
each of the fields

110
00:04:31,720 --> 00:04:34,570
in the named tuple. Now these names must

111
00:04:34,570 --> 00:04:37,000
conform to the rules for Python variable

112
00:04:37,000 --> 00:04:39,670
names, with the added restriction that

113
00:04:39,670 --> 00:04:41,320
they can't start with an underscore,

114
00:04:41,320 --> 00:04:43,180
and that's mentioned in the documentation we

115
00:04:43,180 --> 00:04:45,130
looked at earlier. So in this case, on

116
00:04:45,130 --> 00:04:47,350
line 15, our plant named tuple has

117
00:04:47,350 --> 00:04:50,760
four fields: name, scientific_name,

118
00:04:50,760 --> 00:04:53,860
lifecycle and plant_type.

119
00:04:53,860 --> 00:04:56,560
Now the plant details tuple, on line 16, is

120
00:04:56,560 --> 00:04:58,930
the same but it doesn't have a name

121
00:04:58,930 --> 00:05:00,970
field. That's because it's used in a

122
00:05:00,970 --> 00:05:02,620
dictionary and the name is the

123
00:05:02,620 --> 00:05:04,870
dictionary key, and we can see that if we

124
00:05:04,870 --> 00:05:06,610
go down and have a look at that on line

125
00:05:06,610 --> 00:05:10,480
64 onwards. You can see there

126
00:05:10,480 --> 00:05:12,250
the dictionary set up and the name of being

127
00:05:12,250 --> 00:05:15,250
the key. Now getting back to our

128
00:05:15,250 --> 00:05:17,890
definitions on lines 15 and 16, on line

129
00:05:17,890 --> 00:05:20,140
15 specifically, you can see here that

130
00:05:20,140 --> 00:05:21,940
I used a list to specify the field names.

131
00:05:21,940 --> 00:05:25,240
However, Python also allows a space or

132
00:05:25,240 --> 00:05:27,760
comma separated string, and that can be

133
00:05:27,760 --> 00:05:29,380
useful if you're reading the data from a

134
00:05:29,380 --> 00:05:31,780
file, for example.  So to see what I mean, I

135
00:05:31,780 --> 00:05:33,730
can change that line now, by removing the

136
00:05:33,730 --> 00:05:40,419
left and right square brackets, as well

137
00:05:40,419 --> 00:05:43,480
as the internal apostrophes. So obviously,

138
00:05:43,480 --> 00:05:45,130
leave the one on the left of name. I'll

139
00:05:45,130 --> 00:05:47,260
leave that as it is there, but delete the

140
00:05:47,260 --> 00:05:54,190
rest of them, and you can see they've

141
00:05:54,190 --> 00:05:56,140
removed all the apostrophes

142
00:05:56,140 --> 00:05:57,760
now, and we're just left with an

143
00:05:57,760 --> 00:05:59,200
apostrophe at the start to the left of

144
00:05:59,200 --> 00:06:02,140
name, and to the right of plant_type.

145
00:06:02,140 --> 00:06:04,600
So if we go back,

146
00:06:04,600 --> 00:06:06,610
now, to namedtupletest.py that we

147
00:06:06,610 --> 00:06:09,820
created, we can print the names from our

148
00:06:09,820 --> 00:06:11,260
basic_plants_list

149
00:06:11,260 --> 00:06:13,870
with a for loop. So let's

150
00:06:13,870 --> 00:06:14,890
go ahead and do that. We'll add that code

151
00:06:14,890 --> 00:06:17,560
from line 5 onwards. So I'm going to type for plant in basic_plant_list.

152
00:06:22,210 --> 00:06:25,210
On the next line, after the colon, print plant zero,

153
00:06:32,229 --> 00:06:36,580
and if you run that, no surprises - we get the names

154
00:06:36,580 --> 00:06:39,700
of the plants printed out, and we can

155
00:06:39,700 --> 00:06:41,050
maybe put this over here on the right

156
00:06:41,050 --> 00:06:43,490
hand side,

157
00:06:43,490 --> 00:06:45,080
just so we can see the names a bit

158
00:06:45,080 --> 00:06:47,539
easier. We could do the same with a named

159
00:06:47,539 --> 00:06:49,970
tuple but we can also use the field

160
00:06:49,970 --> 00:06:52,819
name instead. So to do that we just use

161
00:06:52,819 --> 00:06:55,039
dot notation, just as if it was an

162
00:06:55,039 --> 00:06:58,580
attribute of a class instance. So I can

163
00:06:58,580 --> 00:07:01,220
just comment that code out now, on lines

164
00:07:01,220 --> 00:07:04,729
five and six, and on line eight, we'll

165
00:07:04,729 --> 00:07:08,690
start by typing for plant in plants_list

166
00:07:08,690 --> 00:07:13,610
colon, print, plant and

167
00:07:13,610 --> 00:07:20,000
using dot notation, dot and name.

168
00:07:20,000 --> 00:07:22,009
This makes the code more readable, and we

169
00:07:22,009 --> 00:07:23,090
don't have to remember that the name

170
00:07:23,090 --> 00:07:24,919
appears in position zero of the tuple.

171
00:07:24,919 --> 00:07:28,069
So if you run that, we get the same

172
00:07:28,069 --> 00:07:30,710
output. Now we can still use an index if

173
00:07:30,710 --> 00:07:32,599
you want to, but it really doesn't make a

174
00:07:32,599 --> 00:07:35,659
lot of sense. Plant.scientific_name

175
00:07:35,659 --> 00:07:37,789
will give us the second field but

176
00:07:37,789 --> 00:07:42,830
we could also do plant left square

177
00:07:42,830 --> 00:07:46,909
bracket one right square bracket, run, and

178
00:07:46,909 --> 00:07:48,169
see both fields like that.

179
00:07:48,169 --> 00:07:50,270
You can see we're getting the first two

180
00:07:50,270 --> 00:07:52,370
fields printed there. You wouldn't write

181
00:07:52,370 --> 00:07:54,469
code like this, mixing field names

182
00:07:54,469 --> 00:07:56,870
and indexes, but it can be useful to use the

183
00:07:56,870 --> 00:07:58,759
index sometimes, if it's in a loop

184
00:07:58,759 --> 00:08:01,490
control variable, for example. The point

185
00:08:01,490 --> 00:08:02,960
here though is, we don't lose anything

186
00:08:02,960 --> 00:08:05,599
that can be done with ordinary tuples -

187
00:08:05,599 --> 00:08:07,810
we get extra features with named tuples.

188
00:08:07,810 --> 00:08:10,639
named tuples support all the operations

189
00:08:10,639 --> 00:08:13,130
that you can perform on ordinary tuples.

190
00:08:13,130 --> 00:08:14,780
We can unpack them and iterate over them,

191
00:08:14,780 --> 00:08:17,210
for example, and there's three additional

192
00:08:17,210 --> 00:08:18,800
functions that ordinary tuples don't

193
00:08:18,800 --> 00:08:21,139
have. The documentation covers these well,

194
00:08:21,139 --> 00:08:23,210
but I'll give you an example of the

195
00:08:23,210 --> 00:08:25,490
underscore replace function. Now

196
00:08:25,490 --> 00:08:27,020
the additional functions and two data

197
00:08:27,020 --> 00:08:28,909
attributes have names prefixed

198
00:08:28,909 --> 00:08:31,639
with underscore. Remember, I mentioned earlier

199
00:08:31,639 --> 00:08:33,020
in this video, that you can't use an

200
00:08:33,020 --> 00:08:35,149
underscore before the field names, so

201
00:08:35,149 --> 00:08:36,740
this ensures that there's no conflict

202
00:08:36,740 --> 00:08:39,559
between plant.replace, referring to a

203
00:08:39,559 --> 00:08:41,479
field called replace, and

204
00:08:41,479 --> 00:08:44,420
plant._replace(), referring

205
00:08:44,420 --> 00:08:47,390
to the function. So underscore replace is

206
00:08:47,390 --> 00:08:49,970
a useful way to change the value of one

207
00:08:49,970 --> 00:08:52,339
or more fields in the tuple. Named tuples

208
00:08:52,339 --> 00:08:54,440
are immutable, but you can use the

209
00:08:54,440 --> 00:08:56,360
underscore replace function as a short

210
00:08:56,360 --> 00:08:57,860
and convenient way to

211
00:08:57,860 --> 00:09:00,140
create a new named tuple with some values

212
00:09:00,140 --> 00:09:02,600
changed. So let's have a look how

213
00:09:02,600 --> 00:09:04,670
to go about that. So

214
00:09:04,670 --> 00:09:06,670
on line eleven, I'm just gonna type print

215
00:09:06,670 --> 00:09:10,730
parentheses, space out the output. Then

216
00:09:10,730 --> 00:09:12,790
on line thirteen we'll start with example equals plants_list, then left square bracket,

217
00:09:43,490 --> 00:09:49,130
0, right square bracket, print example. Then on line 15, example equals example._replace, 

218
00:09:49,130 --> 00:09:50,930
lifecycle equals Annual, single quote right square bracket. 

219
00:09:50,930 --> 00:09:53,920
Then we'll print example. So the Andromeda plant is an evergreen.

220
00:09:53,920 --> 00:09:56,420
That's the value of its lifecycle field, so let's just run that.

221
00:09:56,420 --> 00:09:58,430
Alright, so the Andromeda plant is an evergreen.

222
00:09:58,430 --> 00:10:00,860
That's the value of its lifecycle field. This code prints

223
00:10:00,860 --> 00:10:02,810
that out so that we can check, and then use the

224
00:10:02,810 --> 00:10:05,029
underscore replace function to create a

225
00:10:05,029 --> 00:10:07,459
new named tuple with the

226
00:10:07,459 --> 00:10:10,160
life cycle set to annual. If we go scroll

227
00:10:10,160 --> 00:10:12,860
over, we can see that. There's evergreen

228
00:10:12,860 --> 00:10:14,510
on the first line of output, up here,

229
00:10:14,510 --> 00:10:17,269
and it's changed then on the second line

230
00:10:17,269 --> 00:10:18,980
of output to annual, and all the other

231
00:10:18,980 --> 00:10:20,300
fields, note, are keeping their original

232
00:10:20,300 --> 00:10:23,480
values. So we saw how to do something

233
00:10:23,480 --> 00:10:25,550
similar with ordinary tuples, back in

234
00:10:25,550 --> 00:10:27,980
section seven. This is a useful shortcut

235
00:10:27,980 --> 00:10:29,779
and makes it more obvious what the code

236
00:10:29,779 --> 00:10:32,209
is doing. You may want to use this

237
00:10:32,209 --> 00:10:34,040
method if you've read records from a

238
00:10:34,040 --> 00:10:36,829
database, for example. If the data changes, you can

239
00:10:36,829 --> 00:10:39,260
update the tuple and write the changes

240
00:10:39,260 --> 00:10:41,660
back to the database. Well, that's about

241
00:10:41,660 --> 00:10:43,339
all I've got to say about named tuples.

242
00:10:43,339 --> 00:10:45,980
We'll return to any and all in the next

243
00:10:45,980 --> 00:10:48,620
video, and then use these named tuples in

244
00:10:48,620 --> 00:10:51,079
some of the examples. See you in the next

245
00:10:51,079 --> 00:10:53,290
video.

