Python - 类定义中的多个@property语句?

时间:2014-02-20 20:15:47

标签: python class properties decorator python-decorators

快速学习课程。我一直在读,构造函数(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的班级是一个坏主意?

5 个答案:

答案 0 :(得分:6)

不,您可以使用多个@property装饰器来处理您的内心。除了示例作家想象之外,这里没有限制。显然。

如果您需要示例,则使用Python标准库@property

  • numbers为Python中的数字类定义了ABCs。

  • tempfile实现临时文件对象

  • threading提供更高级别的线程支持

  • urlparse用于处理网址和查询字符串。

你把它发现了;多个属性看起来与您发布的完全相同。

答案 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-请随时提供反馈!