Forgetting "()" when calling methods

Alex Martelli aleax at aleax.it
Sat Apr 26 01:29:08 CEST 2003


<posted & mailed>

Frantisek Fuka wrote:

> When I try to call methods, I sometimes forget to include the
> parentheses. Instead of:
> 
> if object.isGreen():
> do something...

I would suggest not using 'object' (and other names of built-in
types) as a name for your own variables, AND not using tabs for
formatting (some tools don't show those reliably -- use spaces,
which get shown reliably everywhere).


> i sometimes write:
> 
> if object.isGreen:
> do something...
> 
> If I understand it correctly, the if statement in this case tests if
> pointer to hasParent method is non-zero, which is of course always True

Well, no "of course" about it -- you might perfectly well have
executed at any previous time

    object.isGreen = 0

and then the if would fail.  Determining whether it's possible that
such an assignment has been done is a hellishly hard problem in the
general case.  (Here you mention "hasParent", but your examples show
"isGreen", so that's what I am using).

> so no error is reported and "do something..." always gets executed, so
> the application behaves in quite different way than I expected.
> 
> You can say to me "Don't forget to always include the parenteses" but

Oh, good, because that's very much the crucial issue;-).

> I'm still curious if this cannot be somehow configured, so that I get
> error when I try to just access the method pointer (".isGreen") instead
> of calling the method (".isGreen()"). I understand that there has to be
> the possibility of accessing the method pointers but I usually don't
> need it and for a beginner like me this makes the applications very hard
> to debug.

I guess one might develop a special version of Python which, when
asked to assess a bound-method object in boolean context, raises an
exception rather than accepting it as 'true'.  That, of course,
would still leave you with lots of problems (I'm sure boolean contexts
don't exhaust the list of places where you forget mandatory parentheses,
and functions and other callables have just the same issues as methods --
in general, you need parentheses to call any callable).
 
It's unlikely that such a special version of Python will be developed,
but you can make a case for it, and write a PEP (Python Enhancement
Proposal).  If Guido van Rossum gets convinced that this would indeed
be an enhancement to Python, then it will get implemented.

In Python as it stands, one COULD design a custom metaclass that,
instead of bound-methods, has its classes' instances return special
objects that raise an exception if assessed in a Boolean context and
otherwise delegate to the underlying bound-method.  For example:

import types

class SpecialWrapper(object):
    def __init__(self, func, inst, cls):
        self.func = func
        self.inst = inst
        self.cls = cls
    def __call__(self, *args, **kwds):
        self.func.__get__(self.inst, self.cls)(*args, **kwds)
    def __nonzero__(self):
        raise TypeError, 'Method used in boolean context'
        
class SpecialWrapDesc(object):
    def __init__(self, func):
        self.func = func
    def __get__(self, inst, cls):
        return SpecialWrapper(self.func, inst, cls)
    
class FF(type):
    def __new__(cls, name, bases, clasdict):
        for atnam, atval in clasdict.iteritems():
            if type(atval) is types.FunctionType:
                clasdict[atnam] = SpecialWrapDesc(atval)
        return type.__new__(cls, name, bases, clasdict)
__metaclass__ = FF

if __name__ == '__main__':
    class X:
        def ciao(self): print 'ciao!'
    x=X()

    # show normal method use works
    x.ciao()

    # show unbound-method use works
    X.ciao(x)

    # show use in boolean context raises an exception:
    if x.ciao:
       print 'oops...'
    else:
        print 'weird...?'


So, if you're willing to copy these three classes ito some
module (say FF.py), and start your own modules with:

import FF
__metaclass__ = FF.FF

then you could have the semantics you require.  Since I'm
typing this in at 1:30 AM with minimal testing, it's quite
likely that I have forgotten some doodad or other, but I
think the general concept is sound and any minor issues that
may arise might be dealt with.

Then, once you've finally learned that nothing gets called
until you provide parentheses, you can pension off these
crutches (or, you might stash them somewhere for the time
when you're ready to study custom metaclasses, descriptors,
and the like -- they might then be interesting examples).


Hope this helps...!

Alex





More information about the Python-list mailing list