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

Posted

技术标签:

【中文标题】Python:如何将多个参数传递给属性 getter?【英文标题】:Python: How to pass more than one argument to the property getter? 【发布时间】:2011-08-08 14:34:30 【问题描述】:

考虑以下示例:

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。

【问题讨论】:

【参考方案1】:

我认为你没有完全理解属性的用途。

如果您创建属性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

【讨论】:

我知道!您可以在我的第一个示例中看到 a.x 调用。 @Rizo:属性不是为此而设计的。【参考方案2】:

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

【讨论】:

这是一个直接的解决方案,但我正在使用非常复杂的 getter 和 setter,并希望继续使用它们,而不必为属性编写单独的函数。 这不能回答我的问题。我现在可以在 python 中使用函数了! :) 我只是想知道是否有某种方法可以强制属性充当函数。 @Rizo 为什么?如果您希望它像函数一样工作,请使用函数(方法)。但是在回答您的问题时,唯一的方法是从带有参数的属性中返回一个可调用对象。然后你会得到一些看起来完全像函数但效率较低的东西。 如果 getter 除了返回一个简单的值(或默认值)之外,它还不是“getter”,而是一个常规函数。 @Rizo:在您给出的示例中,让 调用者 决定如何处理返回值可能更明智。毕竟是 caller 传入条件。【参考方案3】:

一个属性应该只依赖于相关的对象。如果你想使用一些外部参数,你应该使用方法。

【讨论】:

假设你想在一些密码验证后访问一个属性,如果不将该密码传递给 getter,那将如何。 @pentanol 我认为属性方法不是 API 身份验证代码的位置。【参考方案4】:

请注意,您没有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

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

【讨论】:

伙计……这实际上是一个绝妙的主意。希望更多的 API 使用它而不是仅仅使用 setters-getters / only properties。 更多装饰器?它们都支持以这种方式使用,因为装饰器语法只是函数调用和名称重新绑定的糖。 哦,我明白你的意思了 - 更多 API 公开了 setter/getter 方法相关属性。 顺便说一句,如果你使用属性装饰器,理论上你甚至不允许有参数。如果失败,您将收到诸如 <...> object is not callable 之类的错误 这里没有封装的思想。以这种方式使用 getter 是没有意义的。那里的界面坏了。【参考方案5】:

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

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

正如其他人所说,不建议这样做。

【讨论】:

【参考方案6】:

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

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】:

我刚刚遇到了这个问题。我有类 Polynomial() 并且我正在定义一个梯度,如果没有参数,我想返回一个函数或评估是否有参数。我想将渐变存储为一个属性,所以我不需要每次需要使用它时都计算它,并且我想使用@property,所​​以渐变属性是惰性计算的。我的解决方案是使用定义的调用方法定义一个类 Gradient 以返回多项式的 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()

【讨论】:

不确定该解决方案是否有效:如果我说a = A(); print(a.x),结果是 0 - 未初始化的 int 的默认值。解决方案 - 据了解 - 应该是 5 for a.x

以上是关于Python:如何将多个参数传递给属性 getter?的主要内容,如果未能解决你的问题,请参考以下文章

如何将具有多个对象的状态数组作为参数传递给graphql突变?

将多个字符串参数传递给 Python 脚本

将更多/多个参数传递给 Python subprocess.call [重复]

如何将多个原始参数传递给 AsyncTask?

如何将多个原始参数传递给 AsyncTask?

如何将多个参数传递给 Process?