快速学习课程。我一直在读,构造函数(Python中的def init)应该只设置已分配的变量,计算的实例属性应该通过属性设置。此外,使用 @property 优先于 Java风格的getter / setter 。
好的,但是我见过的每一个例子都只设置了一个属性。假设我有一个具有三个复杂属性的对象需要计算,查询等。您如何表示多个 @property getters , setters ,删除者?以下是另一个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
的班级是一个坏主意?
答案 0 :(得分:6)
不,您可以使用多个@property
装饰器来处理您的内心。除了示例作家想象之外,这里没有限制。显然。
如果您需要示例,则使用Python标准库@property
:
等
你把它发现了;多个属性看起来与您发布的完全相同。
答案 1 :(得分:1)
这不是一个坏主意。这是一种常规的房产模式。
另一种模式就是:
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
答案 2 :(得分:0)
它可能很难看,但这就是它的工作方式。通常,pythonic建议不要创建直接访问本机变量的简单setter / getter(除非您知道接口可能会更改)。假设属性的原因是你所说的“复杂计算”,那么看起来有点丑陋的模式没有捷径。请参阅此链接http://tomayko.com/writings/getters-setters-fuxors
答案 3 :(得分:0)
是的,但@property装饰器使得在类中定义多个属性更加整洁。 属性与属性不同。由于python没有内置访问修饰符,因此在封装中使用属性的原因。实际上,当我们在方法上面调用@property decorator时,我们实例化一个属性对象。属性对象是具有 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属性。
答案 4 :(得分:0)
要弹跳另一个答案,
看起来有些丑陋的模式没有捷径
确实不是在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-请随时提供反馈!