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

问题描述 投票:0回答:8

考虑以下示例:

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

所以,我想知道如何将多个参数传递给属性获取器(如果可能的话)。

python properties language-features
8个回答
103
投票

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

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


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

如果您创建属性

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
    

22
投票
属性应该仅依赖于相关对象。如果你想使用一些外部参数,你应该使用方法。


10
投票
在第二个示例中,您使用

a.x()

 就好像它是一个函数:
a.x(neg=True)
。考虑到这一点,为什么不将其定义为函数呢?


9
投票
我知道这个问题很老了,但是,作为参考,您可以使用这样的参数来调用您的属性:

a = A() assert a.x == 5 assert A.x.fget(a, True) == -5
正如其他人提到的,不建议这样做。


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

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
投票
我刚刚遇到这个问题。我有 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()
    

0
投票
有时您需要根据具有有限的不同值的变量选择适当的操作(因为您的不同选择有限)。基本上,您可以通过元组或字典来实现它,但您可以通过定义允许类型的内部类来实现它。

例如,我们可以根据不同的来源生成特定格式的数据,以进行进一步处理:

从 formatted_data 导入 FormattedData

数据生成器类:

class TYPE: CSVFILE = 0 SQLITE = 1 HTTP = 2 @classmethod def produceData(c, source_type: int, source_address) -> FormattedData: match source_type: case c.TYPE.CSVFILE: pass case c.TYPE.SQLITE: pass case c.TYPE.HTTP: pass
调用此类方法:

DataGenerator.produceData(DataGenerator.TYPE.CSVFILE, '/financial_history.csv') DataGenerator.produceData(DataGenerator.TYPE.SQLITE, '/financial_history.sqlite')
    
© www.soinside.com 2019 - 2024. All rights reserved.