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突变?