[Python-Dev] Reasons behind misleading TypeError message when passing the wrong number of arguments to a method
Steven D'Aprano
steve at pearwood.info
Fri May 21 05:54:56 CEST 2010
On Fri, 21 May 2010 10:53:16 am Greg Ewing wrote:
> Ben Finney wrote:
> >>Something like "1 argument in addition to 'self'" would be
> >> reasonably clear and would cover both situations.
> >
> > Except that there's nothing special to the syntax or parser about
> > the name ‘self’.
>
> That's true, but the use of the word 'self' here isn't meant
> to refer to the name of a parameter. The message is aimed at
> the caller of the function, who doesn't necessarily know or
> care what the parameter is actually called.
And who doesn't necessarily know that:
> The important thing is that it represents the object the method
> is being called for, and 'self' is the traditional term used
> when talking about that.
Referring to self in any such error message is going to confuse newbies,
and occasional Python programmers who use it without learning about
object oriented code. E.g. sys admins who use Python as a scripting
language without ever writing their own classes.
Error messages should be aimed at the least capable users (within
reason!) rather than the most capable, since the most capable are:
(1) less likely to make the error in the first place;
(2) more able to interpret the error message correctly;
(3) more likely to understand if the error relates to something "under
the hood"; and
(4) better able to debug the error even in the absence of a useful error
message.
Given this, it is better for the error message to relate to what
the "average" user most likely has in his source code (i.e. a bound
method) rather than what the better-than-average user occasionally uses
(an unbound method).
> I can't think of anything that would
> be more accurate without being excessively verbose or pedantic.
In Python 3.1, strings seem to behave more sensibly IMO:
>>> 'abc'.find()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: find() takes at least 1 argument (0 given)
That looks right to me. I'm calling a *method* with zero arguments
inside the parentheses when I need to call it with one.
If I call it as an unbound method (yes, I know it's actually a function)
I get something more confusing:
>>> str.find('abc')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: find() takes at least 1 argument (0 given)
While calling unbound methods isn't exactly rare, it is a more advanced
thing to do than calling bound methods. If we're stuck with confusing
messages, better to have it occur for the users who are more likely to
be able to interpret it, that is, those advanced enough to use unbound
methods rather than "ordinary" users.
Note that str avoids the "-1 argument" trap:
>>> str.find()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor 'find' of 'str' object needs an argument
Classes behave in the opposite manner: the error message is technically
correct for the less common, more advanced case, but misleading for the
more common, simple case:
>>> class C:
... def method(self, x):
... return x+1
...
>>> C.method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method() takes exactly 2 positional arguments (0 given)
This is exactly right, since C.method is a function object which takes
two arguments, self and x. Because this is a function, we can't change
this (not that we want to!) without impacting the errors you get when
calling functions not associated with a class.
>>> C().method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method() takes exactly 2 positional arguments (1 given)
This is misleading, since C().method is a bound method which takes one
argument, x, not two. I find myself wishing that Python distinguished
between ArgumentError and other TypeErrors, so that the method wrapper
of bound methods could simply catch ArgumentError and subtract 1 from
each argument count.
--
Steven D'Aprano
More information about the Python-Dev
mailing list