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

前端 未结 7 1967
清酒与你
清酒与你 2021-01-31 06:48

Consider the following example:

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

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

相关标签:
7条回答
  • 2021-01-31 07:31

    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()
    
    0 讨论(0)
  • 2021-01-31 07:33

    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?

    0 讨论(0)
  • 2021-01-31 07:34

    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
    
    0 讨论(0)
  • 2021-01-31 07:36

    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
    
    0 讨论(0)
  • 2021-01-31 07:41

    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)

    0 讨论(0)
  • 2021-01-31 07:41

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

    0 讨论(0)
提交回复
热议问题