WEBVTT

1
00:00:00.620 --> 00:00:02.220
<v Instructor>Hi guys and welcome back.</v>

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.

