Positional arguments must be passed in order as declared in the function. So if you pass three positional arguments, they must go to the first three arguments of the function, and those three arguments can't be passed by keyword. If you want to be able to pass the first argument out of order by keyword, all your arguments must be passed by keyword (or not at all, if they have defaults).
If it helps, Python's binding mechanism is roughly:
- Assign positional arguments one by one to sequential parameters of the function. These parameters are now set.
- Assign keyword arguments to remaining parameters in any order. If one of the keyword arguments matches an argument already assigned positionally (or the same keyword argument is passed twice), it's an error.
In your case, what this means is that:
greet('Holmes', first_name='Harry')
first binds 'Holmes'
to first_name
. Then it saw you tried to pass first_name
again as a keyword argument and objected.