【问题标题】:Python - multiple @property statements in class definition?Python - 类定义中的多个@property 语句?
【发布时间】:2014-03-22 00:44:29
【问题描述】:

加快学习课程的进度。我一直在阅读构造函数(Python中的def init)应该只设置分配的变量,计算的实例属性应该通过属性设置。此外,使用 @property 优于 Java 风格的 getter/setter

好的,但是我见过的每个例子都只设置一个属性。假设我有一个具有三个复杂属性的对象,需要计算、查询等。你如何表示多个 @property getterssettersdeleters强>?这是另一个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 的类是个坏主意?

【问题讨论】:

    标签: python class properties decorator python-decorators


    【解决方案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.foomyObj.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 装饰器时,我们实例化了一个属性对象。属性对象是具有getsetdel方法的对象。属性可以在类中定义,而不需要在 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 - 请随时提供反馈!

          【讨论】:

            猜你喜欢
            • 2011-07-24
            • 1970-01-01
            • 2017-07-03
            • 2017-04-23
            • 2018-09-27
            • 2018-09-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多