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

时间:2011-04-19 11:27:36

标签: python properties language-features

考虑以下示例:

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。

7 个答案:

答案 0 :(得分:50)

请注意,您 不能将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

这可能是一个好主意,也可能不是一个好主意,具体取决于你正在做什么(但如果我在我正在审查的任何代码中遇到这种模式,我希望在评论中看到一个很好的理由)< / p>

答案 1 :(得分:32)

我认为你并没有完全理解财产的目的。

如果您创建了一个属性x,则可以使用obj.x代替obj.x()来访问该属性。 创建属性后,不可能直接调用底层函数。

如果要传递参数,请为方法命名get_x,不要将其设为属性:

def get_x(self, neg=False):
    return 5 if not neg else -5

如果你想创建一个setter,可以这样做:

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

    @x.setter
    def x(self, value): self._x = value

答案 2 :(得分:16)

属性应仅依赖于相关对象。如果要使用某些外部参数,则应使用方法。

答案 3 :(得分:11)

在第二个示例中,您使用的是a.x(),就好像它是一个函数:a.x(neg=True)。考虑到这一点,为什么不将它定义为函数?

答案 4 :(得分:5)

我知道这个问题很旧,但是,作为参考,您可以使用这样的参数调用您的属性:

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

正如其他人提到的那样,不建议这样做。

答案 5 :(得分:3)

在这种特殊情况下,您可以定义两个属性,它们调用一个基础函数:

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

答案 6 :(得分:0)

我刚遇到这个问题。我有类Polynomial(),并且正在定义一个渐变,如果没有参数,我想返回一个函数或评估是否有参数。我想将渐变存储为属性,因此我不需要每次使用时都计算它,并且我想使用@property以便渐变计算延迟。我的解决方案是定义一个带有定义的调用方法的Gradient类,以使Polynomial的grad属性返回。

@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

然后我成功通过了以下测试:

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

因此,对于这个问题,我们可以尝试:

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