【问题标题】:What's the difference between a Python "property" and "attribute"?Python“属性”和“属性”有什么区别?
【发布时间】:2011-11-14 13:00:23
【问题描述】:

我通常对“属性”和“属性”之间的区别感到困惑,并且找不到一个很好的资源来简明扼要地详细说明这些区别。

【问题讨论】:

    标签: python


    【解决方案1】:

    属性是一种特殊的属性。基本上,当 Python 遇到如下代码时:

    spam = SomeObject()
    print(spam.eggs)
    

    它在spam 中查找eggs,然后检查eggs 以查看它是否具有__get____set____delete__ 方法 — 如果有,它就是一个属性。如果它一个属性,它会调用__get__方法(因为我们正在查找)而不是仅仅返回eggs对象(因为它会返回任何其他属性)并返回任何东西方法返回。

    更多关于Python's data model and descriptors的信息。

    【讨论】:

    • 听起来属性涉及访问目标值的额外处理......你知道它有多重要/慢得多吗?
    • @martineau:嗯,有一个额外的函数调用,但很可能额外的工作和时间取决于属性正在做什么(一般建议:不要/不要/使用属性来隐藏 I/ O)。
    【解决方案2】:

    有了一个属性,你可以完全控制它的 getter、setter 和 deleter 方法,而这些方法是你没有的(如果不使用警告的话)。

    class A(object):
        _x = 0
        '''A._x is an attribute'''
    
        @property
        def x(self):
            '''
            A.x is a property
            This is the getter method
            '''
            return self._x
    
        @x.setter
        def x(self, value):
            """
            This is the setter method
            where I can check it's not assigned a value < 0
            """
            if value < 0:
                raise ValueError("Must be >= 0")
            self._x = value
    
    >>> a = A()
    >>> a._x = -1
    >>> a.x = -1
    Traceback (most recent call last):
      File "ex.py", line 15, in <module>
        a.x = -1
      File "ex.py", line 9, in x
        raise ValueError("Must be >= 0")
    ValueError: Must be >= 0
    

    【讨论】:

    • 这个(“完全控制”)也可以用“非属性”属性来完成,只是没有这些简单的装饰器。
    • 我喜欢这个答案提供了一个现实而有用的例子。我觉得这个网站上的太多答案不必要地解释了后端是如何工作的,而没有阐明用户应该如何与他们交互。如果人们不明白为什么/何时使用某些功能,那么了解它在幕后的运作方式就毫无意义。
    • 这个答案违反了“Python 之禅——应该有一种——最好只有一种——明显的方法”。有两种方法可以设置 x 值。
    • @TinLuu - 只有一种方法可以设置 x 的值。设置_x 的值也只有一种方法。它们是同一事物的事实是实现细节。这个类的聪明用户不会使用_x。
    • @TinLuu - 我认为我们都在从不同的角度说同样的话。该类的用户只能看到x。单程。如果该课程的用户发现了 _x,他们将自行承担使用它的风险。
    【解决方案3】:

    一般来说,属性和属性是一回事。但是,Python 中有一个属性装饰器,它提供对属性(或其他数据)的 getter/setter 访问。

    class MyObject(object):
        # This is a normal attribute
        foo = 1
    
        @property
        def bar(self):
            return self.foo
    
        @bar.setter
        def bar(self, value):
            self.foo = value
    
    
    obj = MyObject()
    assert obj.foo == 1
    assert obj.bar == obj.foo
    obj.bar = 2
    assert obj.foo == 2
    assert obj.bar == obj.foo
    

    【讨论】:

    • 能否请您提一下这段代码的预期结果?
    • 什么意思?这不是在代码的底部吗?
    【解决方案4】:

    该属性允许您像使用普通属性一样获取和设置值,但在下面有一个称为将其转换为您的 getter 和 setter 的方法。减少调用 getter 和 setter 的样板真的很方便。

    比如说,你有一个类,其中包含一些你需要的东西的 x 和 y 坐标。要设置它们,您可能需要执行以下操作:

    myObj.x = 5
    myObj.y = 10
    

    这比写作更容易观察和思考:

    myObj.setX(5)
    myObj.setY(10)
    

    问题是,如果有一天你的班级发生了变化,你需要将你的 x 和 y 偏移某个值怎么办?现在您需要进入并更改您的类定义和调用它的所有代码,这可能非常耗时且容易出错。该属性允许您使用前一种语法,同时为您提供后一种更改的灵活性。

    在 Python 中,您可以使用属性函数定义 getter、setter 和 delete 方法。如果您只想要 read 属性,还可以在方法上方添加一个 @property 装饰器。

    http://docs.python.org/library/functions.html#property

    【讨论】:

    • 只有实际意义的答案!
    【解决方案5】:

    我从 Bernd Klein 的 site 中学到了 2 个不同之处,总结如下:

    1.属性是实现数据封装更便捷的方式

    例如,假设您有一个公共属性length。稍后,您的项目需要您对其进行封装,即将其更改为私有并提供 getter 和 setter => 您必须更改之前编写的代码:

    # Old code
    obj1.length = obj1.length + obj2.length
    # New code (using private attributes and getter and setter)
    obj1.set_length(obj1.get_length() + obj2.get_length()) # => this is ugly
    

    如果您使用 @property@length.setter => 您不需要更改旧代码。

    2。一个属性可以封装多个属性

    class Person:
      def __init__(self, name, physic_health, mental_health):
        self.name = name
        self.__physic_health = physic_health 
        self.__mental_health = mental_health 
    
      @property
      def condition(self):
        health = self.__physic_health + self.__mental_health
        if(health < 5.0):
          return "I feel bad!"
        elif health < 8.0:
          return "I am ok!"
        else:
          return "Great!"
    

    在本例中,__physic_health__mental_health 是私有的,不能从外部直接访问。

    【讨论】:

      【解决方案6】:

      我用来缓存或刷新数据还有一个不明显的区别,通常我们有一个连接到类属性的函数。例如,我需要读取一次文件并保留分配给属性的内容,以便缓存值:

      class Misc():
              def __init__(self):
                  self.test = self.test_func()
      
              def test_func(self):
                  print 'func running'
                  return 'func value'
      
      cl = Misc()
      print cl.test
      print cl.test
      

      输出:

      func running
      func value
      func value
      

      我们两次访问了该属性,但我们的函数只被触发了一次。将上面的示例更改为使用属性将导致每次访问它时都会刷新属性的值:

      class Misc():
      
          @property
          def test(self):
              print 'func running'
              return 'func value'
      
      cl = Misc()
      print cl.test
      print cl.test
      

      输出:

      func running
      func value
      func running
      func value
      

      【讨论】:

        【解决方案7】:

        我喜欢这样认为,如果你想为属性设置限制,请使用属性。

        虽然所有属性都是公共的,但程序员通常用下划线(_)区分公共属性和私有属性。考虑以下类,

        class A:
            def __init__(self):
                self.b = 3    # To show public
                self._c = 4   # To show private
        

        这里,b 属性旨在从 A 类外部访问。但是,这个类的读者可能想知道,可以从外部类 A 设置b 属性吗?

        如果我们不打算从外部设置b,我们可以用@property 表示这个意图。

        class A:
            def __init__(self):
                self._c = 4   # To show private
           
            @property
            def b(self):
                return 3
        

        现在,b 无法设置。

        a = A()
        print(a.b)   # prints 3
        a.b = 7      # Raises AttributeError
        

        或者,如果您只想设置某些值,

        class A:
            @property 
            def b(self):
                return self._b
            
            @b.setter
            def b(self, val):
                if val < 0:
                    raise ValueError("b can't be negative")
                self._b = val
        
        a = A()
        a.b = 6     # OK
        a.b = -5    # Raises ValueError
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-09-20
          • 2016-04-29
          • 2018-04-28
          • 2021-12-26
          相关资源
          最近更新 更多