I think we have to test this on newbies. [snip]
Now that's talking like a programmer!
Ideas on how such a survey could be conducted? Anyone?
If this dead horse is revived because of that reason, then I'd go with
changing the error message to something that is less confusing to
newbies[1].
+ googol
I remember being tripped with the (thinking that python miscounted the
number of argument) when I was new. This has the advantage of backward
compatibility and no syntax change, just less misleading error message.
[1] anything could work, but I like this one: (c is an instance of
class C)
if the code is: c.foo(...), Error: "TypeError: c.foo() takes exactly 3
argument"
while if the code is: C.foo(...), Error: "C.foo() takes exactly 4
arguments"
You can implement c.foo as a curried C.foo function, catch C.foo's
TypeError exception then reraise it as c.foo exception.
I'm not sure that I'd find that less confusing. Because a c.foo() *does*
take four arguments, not three. It's just that the first one is implicit
(Right?).
It's not implicit, we explicitly pass c (the object instance), although
not in the argument list. So c.foo takes 3 arguments while C.foo takes 4
arguments.
In other words:
from functools import partial
c = C() -> c.attr = partial(C.attr, c)
Note the error message I gave:
"TypeError: c.foo() takes exactly 3 arguments"
"TypeError: C.foo() takes exactly 4 arguments"
There are two differences there, not only one claims to accept three and
the other 4 arguments, but also the capitalization of c/C. Here is a
clearer example:
inst = cls()
"TypeError: inst.foo() takes exactly 3 arguments"
"TypeError: cls.foo() takes exactly 4 arguments"
for comparison, python's current (2.5) error message is:
"TypeError: foo() takes exactly 4 arguments"
in addition, with this proposal we'll know how foo is being called.
The following is a quick and dirty implementation of such error message.
Note: There are still some unresolved problems though:
1. instance.[func name] is hardcoded, as I don't know how to get the
instance's name from the instance creation itself
2. Class Invoking from class gives TypeError: foo()... instead of
TypeError: Class.foo()...
3. most definitely not to be used on real application
from types import MethodType
import re
errmess = re.compile(r'(.*?) (.*?) (\d*) (arguments?) \((\d*) given\)')
def usenewexc(obj):
def wrap(f):
def wrap_(*args, **kargs):
try:
print args, kargs
return f(*args, **kargs)
except TypeError, e:
re_mess = errmess.match(e.message)
fname = re_mess.group(1)
interm = re_mess.group(2) if re_mess.group(3) != '1' else
'takes'
reqargs = int(re_mess.group(3)) - 1 if re_mess.group(3) !
= '1' else 'no'
argue_s = re_mess.group(4) if re_mess.group(3) != '1'
else 'arguments'
givenargs = int(re_mess.group(5)) - 1
raise TypeError('%s.%s %s %s %s (%s given)' %
('instance', fname, interm, reqargs, argue_s, givenargs))
return wrap_
for attrname in dir(obj):
attr = obj.__getattribute__(attrname)
if type(attr) == MethodType:
obj.__setattr__(attrname, wrap(attr))
return obj
class A(object):
def foo(self):
print ''
pass
a = usenewexc(A())
A.foo(a, 2)