Reputation:
I keep getting an error message on my function parameters.
I've seen some other questions that are similar but I struggle to understand the answer and those people also had different situations which were more complex.
def check(user_answer='', list_of_blanks, letters):
x = 0
for letter in letters:
if letter == user_answer:
list_of_blanks[letters.index(user_answer)] = user_answer
x += 1
if x == 0:
return False
else:
str(list_of_blanks)
list_of_blanks = ''.join(list_of_blanks)
return list_of_blanks
pycharm highlights "list_of_blanks, letters" (function parameters) and gives me the error which says:
Non-Default parameter follows default parameter.
If I try to default the parameter to an empty list like so:
list_of_blanks=[], letters=[]
then I get this error:
Default argument value is mutable.
Upvotes: 2
Views: 1921
Reputation: 114230
Giving an argument a default value makes it optional. You can't have optional arguments before non-optional ones because then it becomes unclear which slots you mean to assign and which you don't. You might be able to come up with a complex set of rules to determine how to interpret the arguments, but Python attempts to avoid unnecessary complexity, ambiguity, and counter-intuitive behavior.
You have a number of options available to work around this:
Move the default argument to the end of the list:
def check(list_of_blanks, letters, user_answer=''):
Make all the other arguments optional as well:
def check(user_answer='', list_of_blanks=(), letters=()):
Using tuples, which are immutable, avoids the possibility accidental (and permanent) modification of the default lists.
Remove the default argument entirely:
def check(user_answer, list_of_blanks, letters):
Frankly this seems to be the best option in your case. Conceptually speaking, the most important arguments of a function come first. Unless your function has side-effects, making these arguments optional seems somehow deficient.
Make the other arguments required, but keyword-only:
def check(user_answer='', *, list_of_blanks, letters):
You will no longer be able to invoke the function as check('abc', ['b', 'c'], ['a'])
because list_of_blanks
and letters
can no longer be specified as positional arguments. You must now invoke with keywords as check('abc', list_of_blanks=['b', 'c'], letters=['a'])
. But now the first argument is unambiguously optional, so you can do things like check(letters=['a'], list_of_blanks=['b', 'c'])
.
My personal preference, in decreasing order is 3, 4, 1, 2. I think your best bet is to have no optional arguments, but I can imagine you being in a phase where you'd want to play with keyword-only arguments regardless of the design implications.
Upvotes: 0
Reputation: 5232
You can't have a non-positional argument (param=value
) prior to positional arguments.
def func(positional1, positional2, nonpositional=10)
This is due primarily to the fact you are not required to specify the name of non-positional parameters.
func(10, 50, nonpositional=60)
== func(10, 50, 60)
Upvotes: 4
Reputation: 870
Is it possible to switch positions of the arguments? Then you could just write:
def check(list_of_blanks, letters, user_answer=''):
Upvotes: 2