Reputation: 1363
Is it possible to do something like the following:
class foo():
def bar(): # a method that doesn't take any args
# slow calculation
return somefloat
b = bar # bar is a function but b just gives you the float attribute
f = foo()
f.b # returns somefloat but doesn't require the empty parentheses
I hope the example is clear since I'm not super clear on what the terminology is for what I want to do. My basic goal is to remove a bunch of parentheses for methods that don't have arguments to make the code cleaner to read.
The function is slow and rarely used so it would be easiest to calculate it real time rather than calculate it once ahead of time and store the variable.
Is this possible? Is it good practice? Is there a better way?
Upvotes: 2
Views: 53
Reputation: 59158
The standard way to achieve this is to use property
, which is a decorator:
class Foo():
@property
def bar(self):
# slow calculation
return somefloat
f = Foo()
f.bar # returns somefloat but doesn't require the empty parentheses
A couple of things to notice:
You still need self
in the method signature as usual, because sometimes you're going to need to refer to e.g. self.some_attribute
inside the method. As you can see, that doesn't affect the use of the property at all.
There's no need to clutter your API with both a f.bar()
method and a f.b
property - it's better to decide what makes most sense for your class than offer a heap of different ways to do the same thing.
Upvotes: 3
Reputation: 10223
By static method, but need to call by parentheses.
class foo(object):
@staticmethod
def bar(): # a method that doesn't take any args
# slow calculation
return "abc"
b = bar # bar is a function but b just gives you the float attribute
f = foo()
print f.b()
output:
$ python test.py
abc
Upvotes: 0
Reputation: 882023
b = bar
obviously wouldn't work. However a property would for the simplest "doesn't require the empty parentheses" ask of yours:
b = property(bar)
Now every access to f.b
will call f.bar()
"behind the curtains".
However this means that if you access f.b
twice, f.bar()
gets called twice, repeating the computation. If the repetition is irrelevant (i.e if the result doesn't change for repeated computations on the same object) you can do better ("caching" the result in f.b
forever once it's first been computed) -- something like:
class foo(object):
def bar(self): # a method that doesn't take any args
# slow calculation
return somefloat
def _cache_bar(self):
result = self.bar()
setattr(self, 'b', result)
return result
b = property(_cache_bar)
Upvotes: 2