Python的“属性”和“属性”之间有什么区别?


146

我通常对“属性”和“属性”之间的区别感到困惑,并且找不到合适的资源来简洁地详细说明这些区别。

Answers:


184

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

spam = SomeObject()
print(spam.eggs)

它查找eggsspam,然后检查eggs,看它是否有一个__get____set____delete__方法-如果这样做,这是一个性质。如果它一个属性,则不仅会返回该eggs对象(就像对其他任何属性一样),还会调用该__get__方法(因为我们一直在进行查找),并返回该方法返回的内容。

有关Python的数据模型和描述符的更多信息。


听起来属性似乎需要额外的处理才能访问目标值...您知道它的显着性/慢得多吗?
martineau

@martineau:嗯,有一个额外的函数调用,但是最有可能的额外工作和时间将取决于属性的工作量(一般建议:不要使用属性来隐藏I / O)。
伊桑·弗曼

56

有了属性,您就可以完全控制其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

即使没有这种简单的装饰器,也可以使用“非财产”属性来完成此“完全控制”。

8
我喜欢这个答案提供了一个现实而有用的示例。我觉得这个网站上的太多答案不必要地解释了后端的工作方式,而没有弄清楚用户应该如何与他们交互。如果不了解为什么/何时使用某些功能,那么就不知道它在幕后如何工作。
汤姆(Tom)

这个答案违反了“ Zen of Python-应该有一个-最好只有一个-显而易见的方法”。有两种设置x值的方法。
Tin Luu

@TinLuu-只有一种方法可以设置x的值。只有一种方法可以设置_x的值。它们是同一件事的事实是实现细节。此类的明智用户不使用_x。
点燃

1
@TinLuu-我认为我们都是从相反的角度说同一件事。该课程的用户只能看到x。单程。如果该类的用户发现有关_x的信息,则使用时需自担风险。
点燃

19

一般来说,属性和属性是同一件事。但是,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

1
您能否也提及此代码的预期结果?
Hasan Iqbal

2
你什么意思?这不是在代码的底部吗?
six8

12

该属性使您可以像获取普通属性一样获取和设置值,但是在其下面有一种方法称为为您将其转换为getter和setter。减少调用getter和setter的样板实际上只是一种便利。

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

myObj.x = 5
myObj.y = 10

与编写相比,这看起来更容易思考和思考:

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

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

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

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


仅回答具有实际意义的答案!
Dude156

8

总的来说,我从Bernd Klein的网站中学到了2个区别 :

1.属性是一种更方便的数据封装方式。

例如:如果您具有对象的公共属性长度,那么以后,您的项目需要您对其进行封装,即:将其更改为私有并提供getter和setter =>您必须更改之前编写的许多代码:

#Old codes
obj1.length=obj1.length+obj2.length
#New codes(Using private attibutes and getter and setter)
obj1.set_lenght(obj1.get_length()+obj2.get_length()) #=> this is ugly

如果使用@property和@ lenght.setter =>,则无需更改这些旧代码

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

class Person:
  def __init__(self, name, physic_health, mental_health):
    self.name=name
    self.__physic_health=physic_health #physic_health is real value in range [0, 5.0]
    self.__mental_health=mental_health #mental_health is real value in range [0, 5.0]
  @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是私有的并且不能直接从外部访问,所以类外部与之交互的唯一方法是通过属性condition


8

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

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.