-
Notifications
You must be signed in to change notification settings - Fork 9
Errors about mismatched arguments, especially self #202
Description
I was looking at this question: https://stackoverflow.com/questions/67034823/trying-to-use-the-return-value-from-one-function-in-another-but-getting-undefine
The poster has made all sorts of errors and their code is generally weird, but I'm just going to focus on the fact that they define a method def add_toys(self,toys) which they try to call with add_toys(self,toys). I put the code into futurecoder to see if it could guide them to a fix. friendly and didyoumean correctly suggest self.add_toys to fix the first exception and self.toys for the next one, e.g:
In your program,
add_toysis an unknown name. The local object<Pet object>has an attribute namedadd_toys. Perhaps you should have writtenself.add_toysinstead ofadd_toys.
First of all, I think "The local object <Pet object>" could probably be improved a bit to something like "The local variable self with value <Pet object>". But that's a side point.
My main point is that after you follow the suggestions you get self.add_toys(self,self.toys). This gives the error TypeError: add_toys() takes 2 positional arguments but 3 were given. The explanation given is:
You apparently have called the function add_toys with 3 positional argument(s) while it requires 2 such positional argument(s). Perhaps you forgot self when defining add_toys.
That's a good guess from friendly and I understand why it's that way but in this case it's obviously incorrect.
More generally, the whole matter of auto-binding self in methods is very confusing for beginners, errors along these lines are common, and I can't imagine how confusing it must be to be told that they passed 3 positional arguments when they only passed 2 that they know of. Where is that third argument? What on earth is Python talking about?
For all errors about binding arguments, executing can help a lot:
- Get the executing node
- Check that it's an
ast.Callso you don't get an internal error when handling something likedef __add__(self, other, foo): - Extract the positional and keyword arguments
- Explain what the arguments are to the user, e.g. they passed 2 positional arguments:
selfandself.toys. I imagine "positional argument" sounds scary and confusing to some. - In particular for this issue, whenever the error message says that the user provided
n+1positional arguments but you only seen, you can guess thatselfhas been provided behind the scenes and explain this to the user. This is more general than the above example - it doesn't matter how many arguments the user provided, how many they were supposed to provide, or what the arguments were (e.g. if they passedself), just that discrepancy between the source code and the message. - Even more generally, if you can use
pure_evalto getnode.functhen you will know what they were trying to call. Then withinspect.signatureyou can see what arguments they're supposed to provide and explain how Python attempted to bind them. In this caseinspect.signature(self.add_toys)is just(toys), whileinspect.signature(self.add_toys.__func__)is(self, toys)which might also be useful.