Consider the following example:
class A:
@property
def x(self): return 5
So, of course calling the a = A(); a.x
will retur
I just ran into this issue. I have class Polynomial() and I'm defining a gradient that I would like to return a function if no arguments or evaluate if there are arguments. I want to store the gradient as an attribute so I don't need to calculate it every time I need to use it, and I want to use @property so the gradient attribute is calculated lazily. My solution was to define a class Gradient with a defined call method for Polynomial's grad property to return.
@property
def grad(self):
"""
returns gradient vector
"""
class Gradient(list):
def __call__(self, *args, **kwargs):
res = []
for partial_derivative in g:
res.append(partial_derivative(*args, **kwargs))
return res
g = Gradient()
for i in range(1, len(self.term_matrix[0])):
g.append(self.derivative(self.term_matrix[0][i]))
return g
And then I have the following tests pass successfully:
def test_gradient(self):
f = Polynomial('x^2y + y^3 + xy^3')
self.assertEqual(f.grad, [Polynomial('2xy + y^3'), Polynomial('x^2 + 3xy^2 + 3y^2')])
self.assertEqual(f.grad(x=1, y=2), [12, 25])
f = Polynomial('x^2')
self.assertEqual(f.grad(1), [2])
So, for this issue we could try:
class A:
@property
def x(self):
class ReturnClass(int):
def __call__(self, neg=False):
if not neg:
return 5
return -5
return ReturnClass()
In your second example, you're using a.x()
as if it were a function: a.x(neg=True)
. With this in mind, why not just define it as a function?
In this particular case, you could define two properties, which call an underlying function:
class A:
@property
def x(self):
return self._x(neg = False)
@property
def x_neg(self):
return self._x(neg = True)
def _x(self, neg):
return 5 if not neg else -5
I think you did not fully understand the purpose of properties.
If you create a property x
, you'll accessing it using obj.x
instead of obj.x()
.
After creating the property it's not easily possible to call the underlying function directly.
If you want to pass arguments, name your method get_x
and do not make it a property:
def get_x(self, neg=False):
return 5 if not neg else -5
If you want to create a setter, do it like this:
class A:
@property
def x(self): return 5
@x.setter
def x(self, value): self._x = value
Note that you don't have to use property
as a decorator. You can quite happily use it the old way and expose the individual methods in addition to the property:
class A:
def get_x(self, neg=False):
return -5 if neg else 5
x = property(get_x)
>>> a = A()
>>> a.x
5
>>> a.get_x()
5
>>> a.get_x(True)
-5
This may or may not be a good idea depending on exactly what you're doing with it (but I'd expect to see an excellent justification in a comment if I came across this pattern in any code I was reviewing)
a property should only depend on the related object. If you want to use some external parameters, you should use methods.