Guido's new method definition idea

Lie Ryan lie.1296 at gmail.com
Mon Dec 8 06:16:46 EST 2008


On Sun, 07 Dec 2008 18:27:21 +0100, Andreas Waldenburger wrote:

> On Sat, 6 Dec 2008 23:21:04 -0800 (PST) Lie <Lie.1296 at gmail.com> wrote:
> 
>> 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)


> How about:
> 
> "TypeError: c.foo() takes exactly 3 arguments in addition to the
> implicit instance reference."
> 
> or
> 
> "TypeError: c.foo() takes exactly 4 arguments (5 given, including the
> implicit instance reference)"
> 
> ... or something less kludgy in that general direction. This would
> explain exactly what is wrong.
> 
> /W
> 
> --
> My real email address is constructed by swapping the domain with the
> recipient (local part).





More information about the Python-list mailing list