Skip to content
This repository was archived by the owner on Aug 13, 2021. It is now read-only.
This repository was archived by the owner on Aug 13, 2021. It is now read-only.

Errors about mismatched arguments, especially self #202

@alexmojaki

Description

@alexmojaki

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_toys is an unknown name. The local object <Pet object> has an attribute named add_toys. Perhaps you should have written self.add_toys instead of add_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:

  1. Get the executing node
  2. Check that it's an ast.Call so you don't get an internal error when handling something like def __add__(self, other, foo):
  3. Extract the positional and keyword arguments
  4. Explain what the arguments are to the user, e.g. they passed 2 positional arguments: self and self.toys. I imagine "positional argument" sounds scary and confusing to some.
  5. In particular for this issue, whenever the error message says that the user provided n+1 positional arguments but you only see n, you can guess that self has 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 passed self), just that discrepancy between the source code and the message.
  6. Even more generally, if you can use pure_eval to get node.func then you will know what they were trying to call. Then with inspect.signature you can see what arguments they're supposed to provide and explain how Python attempted to bind them. In this case inspect.signature(self.add_toys) is just (toys), while inspect.signature(self.add_toys.__func__) is (self, toys) which might also be useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions