Beginner friendly error messages for missing self: "TypeError: A.lol() takes 1 positional argument but 2 were given"

Honestly, I’ve been using Python since 15 years ago, and when I get this error I still have to do the whole “what do you mean I passed only one argument oh right it’s a method” in my brain, so a clearer error message would definitely help me.

I wouldn’t say that it’s more common, but it definitely happens regularly. In this case the error message should not point towards an incorrect fix.

4 Likes

Also, there are also scenarios where self may not be the first argument, such as instance methods intended to be used with partial where the ordering of arguments is not what is typical:

In [33]: class Foo:
    ...:     def _impl(x, self):
    ...:         print(f'{self}._impl({x}) called')
    ...:     a = partial(_impl, 'a')
    ...:     b = partial(_impl, 'b')
    ...:     del _impl
    ...: 

In [34]: Foo().a()
<__main__.Foo object at 0x71632be9c6e0>._impl(a) called

I’m not saying it’s a good (or bad) idea to write code like this, but one of the strengths of python is you can write this when it makes sense (and you don’t mind the risk of causing confusion).

1 Like

Then I’ll say it for you: that’s a bad idea :slight_smile: You can do it this way instead:

>>> class Foo:
...     def _impl(self, x):
...         print(f'{self}._impl({x}) called')
...     a = partial(_impl, x='a')
...     b = partial(_impl, x='b')
...     del _impl
...     
>>> Foo().a()
<__main__.Foo object at 0x7f3e18dc70e0>._impl(a) called

Normal parameter order, can still use partial(), no material loss of functionality.

1 Like

Maybe it would be better to give better error messages without guessing. Without guessing, we know that A().lol is a bound method. So, it would be possible that, for bound methods, the message is augmented correspondingly.

>>> A().lol(1)
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    A().lol(1)
    ~~~~~~~^^^
TypeError: A.lol() takes 1 positional argument but 2 were given

The number of given arguments includes the reference to self

or something along this lines.

PyPy has had this error message since a while:

>>>> class A:
....     def lol(a): print(a)
....     
>>>> a = A()
>>>> a.lol(1)
Traceback (most recent call last):
  File "<python-input-2>", line 1, in <module>
    a.lol(1)
TypeError: A.lol() takes 1 positional argument but 2 were given. Did you forget 'self' in the function definition?

it’s triggered under very narrow circumstances (there’s exactly 1 argument too many, the callable is a function, the first argument isn’t named self). I don’t know whether it would be easy to implement this in CPython.

FWIW, I think it would be very worthwhile to improve this problem. there is a paper that analyzed the common pitfalls in the context of object-oriented programming when learning python. the paper identified missing self in method definitions as the most common mistake.

19 Likes

How do decisions get made in the python community? or What is the next step? Who can decide what is good enough here? I’m happy to put up a patch if someone would be interested in mentoring

1 Like

Two things are needed: 1) A core dev who thinks this is a good idea; 2) someone to write a patch, test it, and make sure nothing else breaks.

I’ve seen some favourable views so the first one is likely not a problem, but I also don’t see a firm statement “yes let’s do this” yet. The second one is something pretty much anyone can work on - this should be a reasonably self-contained[1] change and a good way to get familiar with the CPython codebase.


  1. pun intended ↩︎

7 Likes

I think there’s already enough support from others in this thread, but to be explicit: yes, let’s do this. I’m happy to review or assist with a PR implementing this.

7 Likes

Yes, let’s do this. I’m also happy to review and assist.

6 Likes