Python - 类定义中的多个@property 语句?
Posted
技术标签:
【中文标题】Python - 类定义中的多个@property 语句?【英文标题】:Python - multiple @property statements in class definition? 【发布时间】:2014-03-22 00:44:29 【问题描述】:加快学习课程的进度。我一直在阅读构造函数(Python中的def init)应该只设置分配的变量,计算的实例属性应该通过属性设置。此外,使用 @property 优于 Java 风格的 getter/setter。
好的,但是我见过的每个例子都只设置一个属性。假设我有一个具有三个复杂属性的对象,需要计算、查询等。你如何表示多个 @property getters、setters、deleters强>?这是另一个post的例子:
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
所以如果我有三个实例变量是根据其他一些属性计算出来的值,它会不会是这样的
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
@property
def y(self):
"""I'm the 'y' property."""
return self._y
@y.setter
def y(self, value):
self._y = value
@y.deleter
def y(self):
del self._y
@property
def z(self):
"""I'm the 'z' property."""
return self._z
@z.setter
def z(self, value):
self._z = value
@z.deleter
def z(self):
del self._z
或者,我只看到一个 @property
声明这一事实是否意味着拥有一个包含多个 @property
的类是个坏主意?
【问题讨论】:
【参考方案1】:不,您可以随意使用多个 @property
装饰器。显然,除了示例作者的想象之外,这里没有限制。
Python 标准库充满了@property
的使用,如果你想要示例的话:
numbers
为 Python 中的数字类定义 ABC。
tempfile
实现临时文件对象
threading
提供更高级别的线程支持
urlparse
用于处理 URL 和查询字符串。
等等
你看中了它;多个属性看起来与您发布的完全一样。
【讨论】:
【参考方案2】:这不是一个坏主意。这是一个常规的属性模式。
另一种模式是这样的:
class A(object):
def _get_a(self):
return self._a
def _set_a(self, v)
self._a = v
def _del_a(self)
del self._a
a = property(_get_a, _set_a, _del_a)
结果与第一个示例中的相同,您可以随意使用它。在构造函数中初始化 self._a 是个好主意,否则,在调用 self.a 之前访问它会引发 AttributeError
【讨论】:
考虑只使用myObj.foo
或myObj.foo()
而不是myObj.set_foo()
。人们对此有所不同,但一致认为 get_ 通常没有帮助,只会让东西看起来像 Java。
谢谢 我没有考虑初始化。所以我只想说 def __init__(self, a=None): self.a = a?
是的,那将是相同的,并且更加封装。
@ap 我修复了我的代码(在删除器和设置器前加下划线)。看到这些方法是受保护的,并且它们的唯一目的是用作 property() 构造函数的参数,因此它们并不意味着公开访问,它们只是一个示例来说明。我更喜欢 getter、setter 和 deleter 的属性装饰器模式。
赞成以更简洁的形式装饰一组属性访问器。有时较少的垂直代码会提高可读性,特别是如果您有像这样的单行访问器,可以排列为 4 行块加上前导注释。【参考方案3】:
它可能很难看,但这就是它的工作方式。一般来说,pythonic 建议不要创建直接访问本机变量的简单 setter/getter(除非您知道接口可能会更改)。假设属性的原因是您所说的“复杂计算”,那么看起来有些难看的模式没有捷径可走。看这个链接http://tomayko.com/writings/getters-setters-fuxors
【讨论】:
【参考方案4】:是的,但是@property 装饰器使在一个类中定义多个属性变得更加整洁。 属性与属性不同。封装中使用的原因属性是因为 python 没有内置的访问修饰符。事实上,当我们在方法上方调用 @property 装饰器时,我们实例化了一个属性对象。属性对象是具有get、set和del方法的对象。属性可以在类中定义,而不需要在 init 中定义。 init 方法在对象实例化时调用。如果在创建对象时需要设置私有属性,请在 init 中定义它,但当我们不需要初始值时,我们不需要定义属性。这是没有属性的属性示例。
class C(object):
#X Property
@property
def x(self):
"""I'm the 'x' property."""
print('Get The X Property')
return self._x
@x.setter
def x(self, value):
print('X Property Setted to '.format(value))
self._x = value
@x.deleter
def x(self):
print('X is Killed !')
del self._x
#Y Property
@property
def y(self):
"""I'm the 'y' property."""
print('Get The Y Property')
return self._y
@y.setter
def y(self, value):
print('Y Property Setted to '.format(value))
self._y = value
@y.deleter
def y(self):
print('Y is Killed !')
del self._y
当我们需要将 x 和 y 定义为 C 类的属性时。只需在 init 中设置属性即可。因此,x 和 y 列为 C 类属性,并在对象实例化时设置了初始值。
class C(object):
def __init__(self):
self._x = 0
self._y = 0
#X Property
@property
def x(self):
"""I'm the 'x' property."""
print('Get The X Property')
return self._x
@x.setter
def x(self, value):
print('X Property Setted to '.format(value))
self._x = value
@x.deleter
def x(self):
print('X is Killed !')
del self._x
#Y Property
@property
def y(self):
"""I'm the 'y' property."""
print('Get The Y Property')
return self._y
@y.setter
def y(self, value):
print('Y Property Setted to '.format(value))
self._y = value
@y.deleter
def y(self):
print('Y is Killed !')
del self._y
区别很简单。没有任何初始值,类 C 没有 x 和 y 属性。因此,如果我们试图获取该属性,则会引发异常。具有初始值的 C 类从一开始就具有 X 和 Y 属性。
【讨论】:
【参考方案5】:要跳出另一个答案,
看起来有点难看的图案没有捷径
确实不在 python stdlib 中,但现在有一个名为 pyfields
的库以更简洁的方式执行此操作,并且在您不需要验证器而不是转换器时不会牺牲速度。
from pyfields import field, init_fields
class C(object):
x = field(default=None, doc="the optional 'x' property")
y = field(doc="the mandatory 'y' property")
z = field(doc="the mandatory 'z' property")
@init_fields
def __init__(self):
pass
c = C(y=1, z=2)
print(vars(c))
产量
'z': 2, 'y': 1, 'x': None
我是这个库的作者,我写它是因为没有一个existing alternatives 让我满意。
详情请参阅documentation - 请随时提供反馈!
【讨论】:
以上是关于Python - 类定义中的多个@property 语句?的主要内容,如果未能解决你的问题,请参考以下文章