Python: 如何向属性 getter 传递多个参数?

考虑下面的例子:

class A:
@property
def x(self): return 5

因此,当然调用 a = A(); a.x将返回 5

但是假设您希望能够修改属性 x。
这样,例如:

class A:
@property
def x(self, neg = False): return 5 if not neg else -5

a = A(); a.x(neg=True)调用它

这将引发 TypeError: 'int' object is not callable,这很正常,因为我们的 x被评估为 5

因此,如果可能的话,我想知道如何向属性 getter 传递多个参数。

63438 次浏览

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

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?

a property should only depend on the related object. If you want to use some external parameters, you should use methods.

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)

I know this question is old, but, for reference, you can call your property with an argument like that:

a = A()
assert a.x == 5
assert A.x.fget(a, True) == -5

As mentioned by others, this is not advised.

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 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()