1
00:00:00,620 --> 00:00:02,220
Hi guys and welcome back.

2
00:00:02,220 --> 00:00:05,420
In this video we're going to learn about unpacking arguments

3
00:00:05,420 --> 00:00:07,360
and this is a little bit more complicated

4
00:00:07,360 --> 00:00:10,263
than what we've seen so far, so pleased do bear with me.

5
00:00:11,100 --> 00:00:13,660
I'm going to define a multiply function

6
00:00:13,660 --> 00:00:16,680
that takes in any number of arguments.

7
00:00:16,680 --> 00:00:17,513
Here's how.

8
00:00:19,060 --> 00:00:21,900
We create the multiply function as normal,

9
00:00:21,900 --> 00:00:26,123
and in here, we're going to put, star, args.

10
00:00:27,030 --> 00:00:31,040
Now the star is the important part, the args

11
00:00:31,040 --> 00:00:33,580
is just a variable name that will be used

12
00:00:33,580 --> 00:00:36,290
to collect the arguments.

13
00:00:36,290 --> 00:00:38,573
So let's print the args out.

14
00:00:39,730 --> 00:00:41,101
For now it's not going to multiply anything,

15
00:00:41,101 --> 00:00:42,560
it's just going to print them out,

16
00:00:42,560 --> 00:00:44,910
so what's happening here is we've defined a function

17
00:00:44,910 --> 00:00:47,340
and we've said, that the function has

18
00:00:48,780 --> 00:00:53,550
a set of arguments that will be collected into

19
00:00:53,550 --> 00:00:57,720
a tuple of arguments when the function gets called.

20
00:00:57,720 --> 00:01:02,010
So if we do multiply and then we do one, three and five,

21
00:01:02,010 --> 00:01:06,185
notice that here I'm passing different arguments.

22
00:01:06,185 --> 00:01:09,303
But this only has seemingly a single parameter.

23
00:01:09,303 --> 00:01:10,890
So I'm passing three different arguments

24
00:01:10,890 --> 00:01:14,870
and what's gonna happen is they are going to be collected

25
00:01:14,870 --> 00:01:19,870
into this args variable, so I'm gonna save this and run it.

26
00:01:19,950 --> 00:01:22,010
And you can see that what we get printed out

27
00:01:22,010 --> 00:01:25,410
when we run the function is a tuple of my arguments,

28
00:01:25,410 --> 00:01:28,423
so we've got one, three and five printed out as a tuple.

29
00:01:29,370 --> 00:01:32,470
If we wanted to multiply all these numbers together,

30
00:01:32,470 --> 00:01:36,990
we can just iterate over the arguments so for arg in args

31
00:01:36,990 --> 00:01:40,750
we can say total, equal total times arg,

32
00:01:40,750 --> 00:01:45,710
and then return total, then we can print that out.

33
00:01:45,710 --> 00:01:47,330
Now what we're doing here is we're starting off

34
00:01:47,330 --> 00:01:49,710
with a variable which is one and then we're multiplying

35
00:01:49,710 --> 00:01:52,380
that variable each of the arguments,

36
00:01:52,380 --> 00:01:54,330
and then we're returning the final value.

37
00:01:54,330 --> 00:01:59,180
If we run that we get an error because we left the S there

38
00:01:59,180 --> 00:02:01,330
so let's run that again.

39
00:02:01,330 --> 00:02:04,180
There we go we get 15 printed out.

40
00:02:04,180 --> 00:02:08,030
So this is a way collecting multiple arguments

41
00:02:08,030 --> 00:02:11,590
into a single variable when you are calling a function.

42
00:02:11,590 --> 00:02:14,730
And this has a number of uses that you will definitely

43
00:02:14,730 --> 00:02:18,210
be seeing quite a lot as you programme in Python.

44
00:02:18,210 --> 00:02:21,560
Notice that you can call this function with one argument

45
00:02:21,560 --> 00:02:23,980
if you want, and that's totally fine as well,

46
00:02:23,980 --> 00:02:27,170
it just creates a tuple of a single element.

47
00:02:27,170 --> 00:02:29,710
Let's go into another example let's say we have

48
00:02:29,710 --> 00:02:33,190
an add function with two parameters x and y,

49
00:02:33,190 --> 00:02:36,660
and then you have a list of numbers, three and five.

50
00:02:36,660 --> 00:02:40,560
So just as we can use the asterisk to collect arguments

51
00:02:40,560 --> 00:02:44,170
into one parameter, we can go the other way round

52
00:02:44,170 --> 00:02:47,750
and we can use the asterisk to de-structure arguments

53
00:02:47,750 --> 00:02:49,340
into multiple parameters.

54
00:02:49,340 --> 00:02:53,480
So you can do add, star nums, and what this'll do

55
00:02:53,480 --> 00:02:58,240
is it will use three for x and five for y

56
00:02:58,240 --> 00:03:01,550
so it is de-structuring the nums variable

57
00:03:01,550 --> 00:03:04,060
and splitting it out into multiple values

58
00:03:04,060 --> 00:03:07,367
such that one value can go to one parameter.

59
00:03:07,367 --> 00:03:10,170
Notice that if you do just nums here,

60
00:03:10,170 --> 00:03:13,820
you're going to pass three and five, the list itself

61
00:03:13,820 --> 00:03:17,310
as the value for x and y is not going to have a value

62
00:03:17,310 --> 00:03:18,950
so you're going to get an error.

63
00:03:18,950 --> 00:03:23,950
So by doing this it passes one value for each parameter.

64
00:03:23,980 --> 00:03:26,570
Of course you do need to have the same number of values

65
00:03:26,570 --> 00:03:29,210
in this list, as parameters in this function,

66
00:03:29,210 --> 00:03:30,610
otherwise you're going to have an error

67
00:03:30,610 --> 00:03:32,030
where you're gonna have too many parameters

68
00:03:32,030 --> 00:03:33,654
or too many arguments.

69
00:03:33,654 --> 00:03:37,130
Let's print this out so you can check that it works.

70
00:03:37,130 --> 00:03:39,270
There you have it, eight comes out.

71
00:03:39,270 --> 00:03:43,160
Now this can also work with named arguments

72
00:03:43,160 --> 00:03:45,690
so remember you can call the add function

73
00:03:45,690 --> 00:03:49,530
by doing x equals three and y equal five.

74
00:03:49,530 --> 00:03:53,270
So you can do something like that using these asterisks.

75
00:03:53,270 --> 00:03:55,840
Let's say that you've got your nums and these are now

76
00:03:55,840 --> 00:04:00,840
a dictionary with a value for x, and a value for y.

77
00:04:00,940 --> 00:04:04,740
If you wanted to use this dictionary as the argument

78
00:04:04,740 --> 00:04:09,420
to these functions, you would have to do nums x

79
00:04:09,420 --> 00:04:13,700
and nums y, like that, which is kind of ugly

80
00:04:13,700 --> 00:04:15,770
and also difficult to read, you've started to get a lot

81
00:04:15,770 --> 00:04:17,470
of brackets and square brackets and so on.

82
00:04:17,470 --> 00:04:19,940
If you wanted to be even more specific you can do

83
00:04:19,940 --> 00:04:24,580
x equals nums x and y equal nums y.

84
00:04:24,580 --> 00:04:27,740
And here is where the magic happens.

85
00:04:27,740 --> 00:04:29,630
You can see that the parameter name

86
00:04:30,660 --> 00:04:35,170
is the same as the key in the dictionary that we are using

87
00:04:35,170 --> 00:04:40,170
as a value for that parameter, so x is the key x

88
00:04:40,470 --> 00:04:43,220
and y is the key y.

89
00:04:43,220 --> 00:04:47,200
Instead of doing this entire thing, we can tell Python

90
00:04:47,200 --> 00:04:52,200
to pass in this dictionary as named arguments,

91
00:04:52,630 --> 00:04:54,970
where the argument will be equal to the value

92
00:04:54,970 --> 00:04:58,750
associated with that same name for a key.

93
00:04:58,750 --> 00:05:02,240
So essentially doing exactly this, but just do

94
00:05:02,240 --> 00:05:05,940
start star, nums, and that will do the same thing.

95
00:05:05,940 --> 00:05:08,240
So because we're using start star, it will say

96
00:05:08,240 --> 00:05:11,020
okay you've got a dictionary with two keys,

97
00:05:11,020 --> 00:05:13,160
what I'm gonna do is I'm gonna pass in each key

98
00:05:13,160 --> 00:05:16,300
as a named argument, and the value is going to be

99
00:05:16,300 --> 00:05:18,590
that associated with the key, so it'll say

100
00:05:18,590 --> 00:05:21,760
x equals nums x and y equals nums y.

101
00:05:21,760 --> 00:05:24,220
I know that's quite complicated thing,

102
00:05:24,220 --> 00:05:26,760
but it simplifies your code so much

103
00:05:26,760 --> 00:05:29,370
when you can use dictionaries like that.

104
00:05:29,370 --> 00:05:31,960
Let's go back to our multiply function

105
00:05:31,960 --> 00:05:35,750
that we had earlier on with this collected set of arguments.

106
00:05:35,750 --> 00:05:38,310
And I'm going to create anther function called apply

107
00:05:38,310 --> 00:05:42,463
and now we're going to say start args, comma operator.

108
00:05:43,340 --> 00:05:46,030
So this is a special bit of syntax in Python

109
00:05:46,030 --> 00:05:49,930
and what it means is collect all the positional arguments

110
00:05:49,930 --> 00:05:54,510
into this tuple args, and also have

111
00:05:54,510 --> 00:05:57,780
a named argument at the end.

112
00:05:57,780 --> 00:06:02,710
This creates a compulsory or required named argument.

113
00:06:02,710 --> 00:06:04,640
So when you're calling this function you're gonna pass in

114
00:06:04,640 --> 00:06:07,610
as many arguments as you want and they will all be collected

115
00:06:07,610 --> 00:06:11,120
into args and at the end you must pass in

116
00:06:11,120 --> 00:06:13,350
a named argument for this one.

117
00:06:13,350 --> 00:06:16,160
So let me just give it a body there, and we're gonna say

118
00:06:16,160 --> 00:06:18,620
if the operator is equal to the asterisk,

119
00:06:18,620 --> 00:06:21,130
we're going to return multiply of args,

120
00:06:21,130 --> 00:06:23,940
otherwise if the operator is equal to plus,

121
00:06:23,940 --> 00:06:25,620
we're going to return the sum of args

122
00:06:25,620 --> 00:06:27,660
and finally we're going to return no valid operator

123
00:06:27,660 --> 00:06:28,810
if it's neither of them.

124
00:06:28,810 --> 00:06:30,790
Now I have a bug in this function

125
00:06:30,790 --> 00:06:33,300
and you may notice what it is based on

126
00:06:33,300 --> 00:06:35,260
what we've seen already, but I know that you don't have

127
00:06:35,260 --> 00:06:38,430
a lot of practise with this yet so it is possible

128
00:06:38,430 --> 00:06:40,650
to not notice it, that's fine.

129
00:06:40,650 --> 00:06:44,890
We're going to print apply of one three six and seven,

130
00:06:44,890 --> 00:06:47,660
and the operator is going to be plus.

131
00:06:47,660 --> 00:06:49,780
So this is how this function must be called.

132
00:06:49,780 --> 00:06:52,290
You can pass in as many arguments as you want.

133
00:06:52,290 --> 00:06:54,043
They will be collected by args.

134
00:06:54,043 --> 00:06:57,710
Finally you must pass in a named argument

135
00:06:57,710 --> 00:06:59,180
for this one there.

136
00:06:59,180 --> 00:07:02,030
If you just pass in plus, Python's gonna try to

137
00:07:02,030 --> 00:07:05,438
collect it with args, so you're gonna miss this parameter.

138
00:07:05,438 --> 00:07:09,560
Indeed if we run this, you'll see that you get an error.

139
00:07:09,560 --> 00:07:12,590
Missing one required keyword only argument.

140
00:07:12,590 --> 00:07:15,310
So you do need the operator in there.

141
00:07:15,310 --> 00:07:18,700
So if we run this, it'll all work, you get 17 back

142
00:07:18,700 --> 00:07:21,230
because that's the addition of all of these numbers.

143
00:07:21,230 --> 00:07:24,833
However if you change this to a asterisk,

144
00:07:25,880 --> 00:07:30,570
then you get back a tuple, so why this tuple?

145
00:07:30,570 --> 00:07:33,850
Why not the multiplication of all the numbers?

146
00:07:33,850 --> 00:07:37,030
Is there a bug in our multiply function?

147
00:07:37,030 --> 00:07:39,520
Well you might be tempted to go through

148
00:07:39,520 --> 00:07:41,860
and see what the multiply function is doing.

149
00:07:41,860 --> 00:07:45,040
Multiply function starts with a variable called total

150
00:07:45,040 --> 00:07:47,220
that has the value one, and then it goes through

151
00:07:47,220 --> 00:07:50,560
the arguments and makes total equal to

152
00:07:50,560 --> 00:07:53,010
total multiplied by the arg.

153
00:07:53,010 --> 00:07:56,500
So how on earth is it managing to end up

154
00:07:56,500 --> 00:07:58,580
with a tuple being returned?

155
00:07:58,580 --> 00:08:02,260
Well if you multiply by a tuple,

156
00:08:02,260 --> 00:08:04,650
you actually end up with that tuple.

157
00:08:04,650 --> 00:08:09,650
So that means that args must be a tuple of tuples

158
00:08:10,260 --> 00:08:15,260
such that the first argument, the first arg in the tuple

159
00:08:15,272 --> 00:08:18,680
is itself a tuple, such that you're multiplying

160
00:08:18,680 --> 00:08:23,130
the tuple by one, and ending up with the tuple itself

161
00:08:23,130 --> 00:08:26,600
and then returning that, so the best way to do this

162
00:08:26,600 --> 00:08:28,410
is to use a debugger, but we haven't learned

163
00:08:28,410 --> 00:08:29,790
how to use a debugger yet.

164
00:08:29,790 --> 00:08:31,860
So we're gonna print the argumetns and you'll see that

165
00:08:31,860 --> 00:08:33,830
you're gonna get something a little bit weird.

166
00:08:33,830 --> 00:08:37,650
When you print the args, you get a tuple of tuples.

167
00:08:37,650 --> 00:08:39,870
And then when you iterate over the args,

168
00:08:39,870 --> 00:08:42,520
arg is the inner tuple.

169
00:08:42,520 --> 00:08:45,951
You're multiplying that by one, making it equal to the total

170
00:08:45,951 --> 00:08:49,570
such that total is the tuple, and then because that's

171
00:08:49,570 --> 00:08:53,150
the only value in args, that is the end of the for loop

172
00:08:53,150 --> 00:08:54,910
and you return the tuple.

173
00:08:54,910 --> 00:08:59,000
The reason for that is because we did not pass in

174
00:08:59,000 --> 00:09:01,580
individual arguments to the multiply function,

175
00:09:01,580 --> 00:09:02,963
we passed in a tuple.

176
00:09:04,010 --> 00:09:06,540
We want to put a star here.

177
00:09:06,540 --> 00:09:08,310
The reason for that is because when we call

178
00:09:08,310 --> 00:09:11,540
the apply function we are passing in four different

179
00:09:11,540 --> 00:09:13,430
arguments that are being collected

180
00:09:13,430 --> 00:09:16,850
into one tuple, by this star.

181
00:09:16,850 --> 00:09:19,330
But when we call the multiply function,

182
00:09:19,330 --> 00:09:22,360
we wanna pass in four different arguments

183
00:09:22,360 --> 00:09:25,630
so that they can be collected by args,

184
00:09:25,630 --> 00:09:29,410
inside the multiplier function and then used in here.

185
00:09:29,410 --> 00:09:32,460
But before, we were passing the args tuple itself,

186
00:09:32,460 --> 00:09:34,590
the collected tuple in this function.

187
00:09:34,590 --> 00:09:38,350
What we wanna do is we wanna unpack it into four values

188
00:09:38,350 --> 00:09:41,590
and pass them as individual values to this function

189
00:09:41,590 --> 00:09:44,920
so that they can be re-collected by args here.

190
00:09:44,920 --> 00:09:47,530
The other option is to remove the star

191
00:09:47,530 --> 00:09:49,970
so that you are passing a tuple directly

192
00:09:49,970 --> 00:09:52,940
to the multiplier function, and then moving this star

193
00:09:52,940 --> 00:09:56,150
so that the multiply function won't try to collect

194
00:09:56,150 --> 00:09:59,520
all its positional arguments into another tuple.

195
00:09:59,520 --> 00:10:02,740
However I do like passing multiple different arguments

196
00:10:02,740 --> 00:10:04,500
so I'm going to keep this stars there,

197
00:10:04,500 --> 00:10:05,820
but that's a choice for you to make,

198
00:10:05,820 --> 00:10:09,160
you can either pass arguments, or you can pass a tuple.

199
00:10:09,160 --> 00:10:11,830
That is a very common problem and quite a difficult

200
00:10:11,830 --> 00:10:13,890
to diagnose problem as well.

201
00:10:13,890 --> 00:10:15,690
So I just wanted to go through it so that

202
00:10:15,690 --> 00:10:17,400
if you encounter that in the future,

203
00:10:17,400 --> 00:10:18,510
you'll know what's going on.

204
00:10:18,510 --> 00:10:19,880
Thanks for joining me in this video.

205
00:10:19,880 --> 00:10:22,070
Hope it's been useful and not too confusing.

206
00:10:22,070 --> 00:10:23,720
And I'll see you in the next one.

