Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between a Python "property" and "attribute"?

Tags:

python

People also ask

What is the difference between property and attribute?

An attribute is a quality or character ascribed to or considered to belong to, or be inherent in, a person or thing. A property is a quality or characteristic belonging to a person or thing, with its original use implying ownership, and also either being essential or special.

What is property attribute in Python?

The property() method in Python provides an interface to instance attributes. It encapsulates instance attributes and provides a property, same as Java and C#. The property() method takes the get, set and delete methods as arguments and returns an object of the property class.

What is the difference between attribute and function in Python?

A variable stored in an instance or class is called an attribute. A function stored in an instance or class is called a method.


Properties are a special kind of attribute. Basically, when Python encounters the following code:

spam = SomeObject()
print(spam.eggs)

it looks up eggs in spam, and then examines eggs to see if it has a __get__, __set__, or __delete__ method — if it does, it's a property. If it is a property, instead of just returning the eggs object (as it would for any other attribute) it will call the __get__ method (since we were doing lookup) and return whatever that method returns.

More information about Python's data model and descriptors.


With a property you have complete control on its getter, setter and deleter methods, which you don't have (if not using caveats) with an attribute.

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

In general speaking terms a property and an attribute are the same thing. However, there is a property decorator in Python which provides getter/setter access to an attribute (or other data).

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

The property allows you to get and set values like you would normal attributes, but underneath there is a method being called translating it into a getter and setter for you. It's really just a convenience to cut down on the boilerplate of calling getters and setters.

Lets say for example, you had a class that held some x and y coordinates for something you needed. To set them you might want to do something like:

myObj.x = 5
myObj.y = 10

That is much easier to look at and think about than writing:

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

The problem is, what if one day your class changes such that you need to offset your x and y by some value? Now you would need to go in and change your class definition and all of the code that calls it, which could be really time consuming and error prone. The property allows you to use the former syntax while giving you the flexibility of change of the latter.

In Python, you can define getters, setters, and delete methods with the property function. If you just want the read property, there is also a @property decorator you can add above your method.

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


I learnt 2 differences from site of Bernd Klein, in summary:

1. A property is a more convenient way to achieve data encapsulation

For example, let's say you have a public attribute length. Later on, your project requires you to encapsulate it, i.e. to change it to private and provide a getter and setter => you have to change the the code you wrote before:

# 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

If you use @property and @length.setter => you don't need to change that old code.

2. A property can encapsulate multiple attributes

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!"

In this example, __physic_health and __mental_health are private and cannot be accessed directly from outside.