Python: How to pass more than one argument to the property getter?

放肆的年华 提交于 2019-12-03 06:11:24

问题


Consider the following example:

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

So, of course calling the a = A(); a.x will return 5

But imagine that you want to be able to modify the property x.
This way, for example:

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

And call it with a = A(); a.x(neg=True)

That will raise a TypeError: 'int' object is not callable, that is quite normal, since our x is evaluated as 5.

So, I would like to know how one can pass more then one argument to the property getter, if it is possible at all.


回答1:


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)




回答2:


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



回答3:


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




回答4:


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?




回答5:


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 other mentioned by others, this is not advised.




回答6:


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



回答7:


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


来源:https://stackoverflow.com/questions/5715620/python-how-to-pass-more-than-one-argument-to-the-property-getter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!