staggart
staggart

Reputation: 368

Is it possible to have a python class attribute be callable without ()

I want to do something a bit strange. I want to be able to access a class attribute that can be accessed as either a non-function or function:

class foo(object):
    def __init__(self):
        self.x = 99
    def x(self, *args, **kwargs ):
        print "x was called, args=%r, kwargs=%r" % (args, kwargs)
        return( self.x )  # return something useful here...

f = foo()
    print f.x  # prints "x was called", 99
    print f.x() # prints "x was called", 99

Upvotes: 0

Views: 443

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1122502

No idea why you would want to do that, but here is one way, using the property decorator:

class Foo(object):
    @property
    def x(self):
        print "x was called"
        return lambda: None

but this is completely nonsensical. It'll achieve what your example tries to do, but when you access Foo().x a lambda function is returned that is otherwise useless.

If you are fine with returning instances of a custom class, then you can also give that custom class a __call__() method that simply returns self to give .x() slightly more meaning:

class XReturnValue(object):
    def __call__(self):
        return self

class Foo(object):
    @property
    def x(self):
        print "x was called"
        return XReturnValue()

where XReturnValue could be fleshed out more to actually mean something to the user of Foo.x.

However, in Python callables (such as functions and methods) are objects in and of themselves. You can manipulate them, add attributes to them, assign them to different variables for later use, etc. To get their result you call them, but if you don't call them you can retrieve that reference to be re-used elsewhere. You should not try and circumvent that.

In other words, either stick with .x being an attribute, a property, or a method, but don't try to be all at once.

Upvotes: 3

Related Questions