【问题标题】:Python - what's the difference between @property and setting in __init__()?Python - @property 和 __init__() 中的设置有什么区别?
【发布时间】:2017-09-02 02:35:12
【问题描述】:

无法从其他线程中得到直接的答案:

在Python中,使用和使用的主要区别是什么

class Foo(object):
  def __init__(self, x):
    self.x = x

class Foo(object):
  def __init__(self, x):
    self._x = x

  @property
  def x(self):
    return self._x

从外观上看,以这种方式使用@property 会使 x 只读.. 但也许有人有更好的答案?谢谢/弗雷德

【问题讨论】:

    标签: python properties


    【解决方案1】:

    对于您的示例,是的,这允许您拥有只读属性。此外,属性可以让您看起来拥有比实际更多的属性。考虑一个带有.radius.area 的圆圈。面积可以根据半径计算出来,而不需要两个都存储

    import math
    
    class Circle(object):
        def __init__(self, radius):
            self.radius = radius
    
        @property
        def area(self):
            return math.pi * (self.radius ** 2)
    

    【讨论】:

      【解决方案2】:

      property 装饰器实现使用descriptor protocol,这就是我们在 Python OOP 中进行数据封装的方式。描述符是:

      通常,描述符是具有“绑定”的对象属性 行为”,其属性访问已被方法覆盖 在描述符协议中。这些方法是__get__()__set__()、 和__delete__()。如果为对象定义了这些方法中的任何一个, 据说是描述符。

      通常,在其他 OOP 语言中,您使用 getter 和 setter。你会经常看到来自 Java 的人编写这样的 Python 类:

      class A(object):
          def __init__(self, x, y):
              self._x = x
              self._y = y
          def getX(self):
              return self._x
          def getY(self):
              return self._y
          def setX(self, x):
              self._x = x
          def setY(self, y):
              self._y = y
          def some_method_that_uses_attributes(self):
              return self.getX() + self.getY()
      

      这很不是你在 Python 中做事的方式。 getter 和 setter 的重点是提供数据封装。我们通过将数据属性包装在 getter 和 setter 中来封装对数据属性的访问。然后,如果我们想要添加一些东西,比如说,确保 x 永远不会设置为低于 10 的值(作为一个人为的示例),我们只需更改 setX 的实现方式,我们不必修改我们的其余代码。然而,在 Python 中,我们将上面的类编写如下:

      class A(object):
          def __init__(self, x, y):
              self.x = x
              self.y = y
          def some_method_that_uses_attributes(self):
              return self.x + self.y
      

      来自 Java 的人可能会惊恐地退缩:“你没有正确封装你的类!这将成为维护的噩梦!”

      不,因为我们有描述符/属性:

      class A(object):
          def __init__(self, x, y):
              self._x = x
              self.y = y
          @property
          def x(self):
              return self._x
          @x.setter
          def x(self, val):
              if val > 10:
                  self._x = val
              else:
                  raise ValueError("x must be greater than 10")
          def some_method_that_uses_attributes(self):
              return self.x + self.y
      

      现在,我们不必对每个使用self.x 的方法进行折射,例如some_method_that_uses_attributes。更重要的是,当我们进行此更改时,我们类的客户端没有损坏的接口!这很好,因为它让我们避免编写一堆样板代码,并且在我们确实需要它的情况下实现描述符相对简单。此外,这使我们的代码变得漂亮漂亮,没有self.get_this()self.set_that(3) 贯穿整个代码,而self.thisself.that = 3 更具可读性

      【讨论】:

      • 不要说property 实现了描述符协议(误导和不正确)。相反,property 实现使用描述符协议。
      【解决方案3】:

      查看这篇关于 Python 属性的 SO 帖子 - 它专门指的是 getter/setter,但答案更多地涉及它们,我相信你想知道的一切都在那里:Python @property versus getters and setters

      【讨论】:

        猜你喜欢
        • 2012-11-01
        • 2010-10-22
        • 2012-03-28
        • 2011-06-29
        • 2018-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多