There are several reasons that prevents you to do what you are trying to do:
- You can specify a keyword only once in a function call, hence
color=something, ..., color=other
raises an exception
- You cannot mix keyword arguments and positionals, so
x1, y1, color=something, x2
is an error.
Even if this worked as you expected, there's still matplotlib
s documentation that states:
If you make multiple lines with one plot command, the kwargs apply to
all those lines
I.e. you cannot use color=
for only one of the lines, or once for each line. It's a "global" property. You have to use the other ways of providing line colors if you want to specify a different color for each line.
I believe, by your question, that you do not have clear how positional and keyword arguments work so I'll try to give you a clue in this regard.
First of all, there are different kind of parameters. I shall introduce an example to explain the differences:
def a_function(pos_kw1, pos_kw2, *args, kw_only)
This function has:
- Two parameters
pos_kw1
, pos_kw2
which can be assigned both by a positional argument or a keyword argument
- A parameter
*args
that can be specified only with positional arguments
- A parameter
kw_only
that can be specified only with a keyword argument
Note: default values have nothing to do with being keyword parameters. They simply make the parameter not required.
To understand the mechanics of argument passing you can think as (although it's not strictly true) if when python performs a function call (e.g.):
a_function(1, 2, *'abc', kw_only=7)
It first collects all positional arguments into a tuple. In the case above the resultant tuple would be pos_args = (1, 2, 'a', 'b', 'c')
, then collects all keyword arguments into a dict
, in this case kw_args = {'kw_only': 7}
, afterwards, it calls the function doing:
a_function(*pos_args, **kw_args)
Note: since dict
s are not ordered the order of the keywords doesn't matter.
In your question you wanted to do something like:
plot(x, y, color=X, x2, y2, color=Y, ...)
Since the call is actually using *pos_args
and **kw_args
the function:
- Doesn't know that
color=X
was specified right after y
.
- Doesn't know that
color=Y
was specified right after y2
.
- Doesn't know that
color=X
was specified before color=Y
.
Corollary: you cannot specify the same argument more than once since python has no way to know which occurrence should be assigned to which parameter. Also when defining the function you simply couldn't use two parameters with the same name.
(And no, python does not automatically build a list of values or similar. It simply raises an error.)
You can also think that python first expands *pos_args
without taking keyword arguments into account, and after that it expands **kw_args
. If you think in this terms you can clearly understand that a function call such as:
# naive intent: assign pos_kw1 via keyword and pos_kw2 via positional
# assuming python will skip positional that were already provided as keyword args
a_function(1, pos_kw1=2)
# or even:
a_function(pos_kw1=2, 1) # hoping order matters
doesn't have any sense because the 1
is assigned to pos_kw1
via positional arguments, and when expanding the keyword arguments it would be reassigned.
Explained in an other way, in the call a_function(*pos_args, **kw_args)
the *pos_args
is a simple tuple-unpacking operation, equivalent to:
pos_kw1, pos_kw2, *args = pos_args
(in python2 you cannot use the *
, but that's how the *args
parameters work more or less).
Tuple-unpacking doesn't skip elements: it simply assign to consecutive elements of the tuple, and so do function calls: there is no check if a positional argument was already passed via keyword and eventually it's skipped. They are simply assigned, blindly.
Due to these restrictions it doesn't make any sense to allow function calls where positionals appear after keyword arguments hence you cannot do something like:
plot(x, y, color=X, x2, ...)
Allowing such function calls would only trick people making them think that order matters for keywords or that arguments could be skipped when unpacking etc. so Python simply raises an error and avoids this kind of ambiguity.