Instructor: Hi guys and welcome back.
In this video we're going to learn about unpacking arguments
and this is a little bit more complicated
than what we've seen so far, so pleased do bear with me.
I'm going to define a multiply function
that takes in any number of arguments.
Here's how.
We create the multiply function as normal,
and in here, we're going to put, star, args.
Now the star is the important part, the args
is just a variable name that will be used
to collect the arguments.
So let's print the args out.
For now it's not going to multiply anything,
it's just going to print them out,
so what's happening here is we've defined a function
and we've said, that the function has
a set of arguments that will be collected into
a tuple of arguments when the function gets called.
So if we do multiply and then we do one, three and five,
notice that here I'm passing different arguments.
But this only has seemingly a single parameter.
So I'm passing three different arguments
and what's gonna happen is they are going to be collected
into this args variable, so I'm gonna save this and run it.
And you can see that what we get printed out
when we run the function is a tuple of my arguments,
so we've got one, three and five printed out as a tuple.
If we wanted to multiply all these numbers together,
we can just iterate over the arguments so for arg in args
we can say total, equal total times arg,
and then return total, then we can print that out.
Now what we're doing here is we're starting off
with a variable which is one and then we're multiplying
that variable each of the arguments,
and then we're returning the final value.
If we run that we get an error because we left the S there
so let's run that again.
There we go we get 15 printed out.
So this is a way collecting multiple arguments
into a single variable when you are calling a function.
And this has a number of uses that you will definitely
be seeing quite a lot as you programme in Python.
Notice that you can call this function with one argument
if you want, and that's totally fine as well,
it just creates a tuple of a single element.
Let's go into another example let's say we have
an add function with two parameters x and y,
and then you have a list of numbers, three and five.
So just as we can use the asterisk to collect arguments
into one parameter, we can go the other way round
and we can use the asterisk to de-structure arguments
into multiple parameters.
So you can do add, star nums, and what this'll do
is it will use three for x and five for y
so it is de-structuring the nums variable
and splitting it out into multiple values
such that one value can go to one parameter.
Notice that if you do just nums here,
you're going to pass three and five, the list itself
as the value for x and y is not going to have a value
so you're going to get an error.
So by doing this it passes one value for each parameter.
Of course you do need to have the same number of values
in this list, as parameters in this function,
otherwise you're going to have an error
where you're gonna have too many parameters
or too many arguments.
Let's print this out so you can check that it works.
There you have it, eight comes out.
Now this can also work with named arguments
so remember you can call the add function
by doing x equals three and y equal five.
So you can do something like that using these asterisks.
Let's say that you've got your nums and these are now
a dictionary with a value for x, and a value for y.
If you wanted to use this dictionary as the argument
to these functions, you would have to do nums x
and nums y, like that, which is kind of ugly
and also difficult to read, you've started to get a lot
of brackets and square brackets and so on.
If you wanted to be even more specific you can do
x equals nums x and y equal nums y.
And here is where the magic happens.
You can see that the parameter name
is the same as the key in the dictionary that we are using
as a value for that parameter, so x is the key x
and y is the key y.
Instead of doing this entire thing, we can tell Python
to pass in this dictionary as named arguments,
where the argument will be equal to the value
associated with that same name for a key.
So essentially doing exactly this, but just do
start star, nums, and that will do the same thing.
So because we're using start star, it will say
okay you've got a dictionary with two keys,
what I'm gonna do is I'm gonna pass in each key
as a named argument, and the value is going to be
that associated with the key, so it'll say
x equals nums x and y equals nums y.
I know that's quite complicated thing,
but it simplifies your code so much
when you can use dictionaries like that.
Let's go back to our multiply function
that we had earlier on with this collected set of arguments.
And I'm going to create anther function called apply
and now we're going to say start args, comma operator.
So this is a special bit of syntax in Python
and what it means is collect all the positional arguments
into this tuple args, and also have
a named argument at the end.
This creates a compulsory or required named argument.
So when you're calling this function you're gonna pass in
as many arguments as you want and they will all be collected
into args and at the end you must pass in
a named argument for this one.
So let me just give it a body there, and we're gonna say
if the operator is equal to the asterisk,
we're going to return multiply of args,
otherwise if the operator is equal to plus,
we're going to return the sum of args
and finally we're going to return no valid operator
if it's neither of them.
Now I have a bug in this function
and you may notice what it is based on
what we've seen already, but I know that you don't have
a lot of practise with this yet so it is possible
to not notice it, that's fine.
We're going to print apply of one three six and seven,
and the operator is going to be plus.
So this is how this function must be called.
You can pass in as many arguments as you want.
They will be collected by args.
Finally you must pass in a named argument
for this one there.
If you just pass in plus, Python's gonna try to
collect it with args, so you're gonna miss this parameter.
Indeed if we run this, you'll see that you get an error.
Missing one required keyword only argument.
So you do need the operator in there.
So if we run this, it'll all work, you get 17 back
because that's the addition of all of these numbers.
However if you change this to a asterisk,
then you get back a tuple, so why this tuple?
Why not the multiplication of all the numbers?
Is there a bug in our multiply function?
Well you might be tempted to go through
and see what the multiply function is doing.
Multiply function starts with a variable called total
that has the value one, and then it goes through
the arguments and makes total equal to
total multiplied by the arg.
So how on earth is it managing to end up
with a tuple being returned?
Well if you multiply by a tuple,
you actually end up with that tuple.
So that means that args must be a tuple of tuples
such that the first argument, the first arg in the tuple
is itself a tuple, such that you're multiplying
the tuple by one, and ending up with the tuple itself
and then returning that, so the best way to do this
is to use a debugger, but we haven't learned
how to use a debugger yet.
So we're gonna print the argumetns and you'll see that
you're gonna get something a little bit weird.
When you print the args, you get a tuple of tuples.
And then when you iterate over the args,
arg is the inner tuple.
You're multiplying that by one, making it equal to the total
such that total is the tuple, and then because that's
the only value in args, that is the end of the for loop
and you return the tuple.
The reason for that is because we did not pass in
individual arguments to the multiply function,
we passed in a tuple.
We want to put a star here.
The reason for that is because when we call
the apply function we are passing in four different
arguments that are being collected
into one tuple, by this star.
But when we call the multiply function,
we wanna pass in four different arguments
so that they can be collected by args,
inside the multiplier function and then used in here.
But before, we were passing the args tuple itself,
the collected tuple in this function.
What we wanna do is we wanna unpack it into four values
and pass them as individual values to this function
so that they can be re-collected by args here.
The other option is to remove the star
so that you are passing a tuple directly
to the multiplier function, and then moving this star
so that the multiply function won't try to collect
all its positional arguments into another tuple.
However I do like passing multiple different arguments
so I'm going to keep this stars there,
but that's a choice for you to make,
you can either pass arguments, or you can pass a tuple.
That is a very common problem and quite a difficult
to diagnose problem as well.
So I just wanted to go through it so that
if you encounter that in the future,
you'll know what's going on.
Thanks for joining me in this video.
Hope it's been useful and not too confusing.
And I'll see you in the next one.