I am designing the API for a Python library, and have run into a situation where I think my imagination might have overtaken Python’s considerable abilities.
(I want to apologize to any Pythonistas who may get offended by the Ruby-ness of my design)
Basically, there is a class with a few methods on it, each of which returns self, so that they can be chained together. So:
>>> a = MyKlass()
>>> b = a.method_one()
>>> c = b.method_two()
would be the same as
>>> a = MyKlass()
>>> c = a.method_one().method_two()
My question is whether it is possible to make the parenthesis optional. I have learned a bit about using __getattr__ and __call__ to manipulate callable objects, but haven’t been able to fully implement this. Right now, I have the class’s __getattr__ checking for the attribute, and then determining whether the name is a method or attribute (or more accurately, whether it is callable or not).
My problem is that if it is a callable, I need __getattr__ to do something like this:
>>> class MyKlass(object):
>>> def __getattr__(self, name):
>>> # pseudocode, you get the idea...
>>> if name is callable:
>>> def callme(*args, **kwds):
>>> # do stuff
>>> return callme
>>> else:
>>> # just return the attribute
So it returns a callable object. This means, though, that I couldn’t make the parenthesis optional, since the callable object would be returned, but never called:
>>> a = MyKlass()
>>> c = a.method_one.method_two # AttributeError, since a bound function object does not have attribute "method_two"
The only way I thought of to do this would be to be able to “look ahead” in the code and determine whether the name is followed by parenthesis or not. Then, if name was callable but not called, I could return the results of calling name without arguments instead of returning a callable object.
I am thinking that this is probably not doable, but I thought that I would ask the gurus anyway.
I think you’re nuts for wanting to do this. What reason do you have? What about methods that take arguments? (See example below.)
It seems to work for methods without arguments if you use
__getattribute__instead of__getattr__.Working example:
To get around the argument issue, you could inspect the function and only call it if it doesn’t take any arguments (other than self). See: http://docs.python.org/library/inspect.html
Do yourself a favor and stop going down this path.