Reputation: 17741
I am generally confused about the difference between a "property" and an "attribute", and I can't find a great resource to concisely detail the differences.
Upvotes: 243
Views: 94435
Reputation: 631
For one use case, I use @property
to load data on demand and cache
class Foo:
def __init__(self):
self._bar = None
@property
def bar(self):
if _bar is None:
_bar = self.load_bar_dataset_from_database()
return _bar
When my fields contain dataframes for analysis, they are loaded when first accessed and I don't initialize the whole object by loading dataframes from the database all at once, but can also be cached to use in further analysis.
Also prevents "setting" for consistency.
Upvotes: 0
Reputation: 69031
Properties are a special kind of attribute. Basically, when Python encounters the following code:
spam = SomeObject()
print(spam.eggs)
it looks up eggs
in SomeObject
1, and then examines eggs
to see if it has a __get__
, __set__
, or __delete__
method -- if it does, it's a property, and Python will call the __get__
method (since we were doing lookup) and return whatever that method returns. If it is not a property, then eggs
is looked up in spam
, and whatever is found there will be returned.
More information about Python's data model and descriptors.
1 Many thanks to Robert Seimer for the correction on the lookup sequence.
Upvotes: 252
Reputation: 13
Attribute is actually at the object.
Property is propagated by proxy. (Its value may be calculated on the fly.)
See also
Upvotes: 0
Reputation: 400
I like to think that, if you want to set a restriction for an attribute, use a property.
Although all attributes are public, generally programmers differentiate public and private attributes with an underscore(_
). Consider the following class,
class A:
def __init__(self):
self.b = 3 # To show public
self._c = 4 # To show private
Here, b
attribute is intended to be accessed from outside class A. But, readers of this class might wonder, can b
attribute be set from outside class A
?
If we intend to not set b
from outside, we can show this intention with @property
.
class A:
def __init__(self):
self._c = 4 # To show private
@property
def b(self):
return 3
Now, b
can't be set.
a = A()
print(a.b) # prints 3
a.b = 7 # Raises AttributeError
Or, if you wish to set only certain values,
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
Upvotes: 10
Reputation: 1687
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.
Upvotes: 19
Reputation: 12395
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
Upvotes: 108
Reputation: 269
There is also one not obvious difference that i use to cache or refresh data , often we have a function connected to class attribute. For instance i need to read file once and keep content assigned to the attribute so the value is cached:
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
Output:
func running
func value
func value
We accessed the attribute twice but our function was fired only once. Changing the above example to use property will cause attribute's value refresh each time you access it:
class Misc():
@property
def test(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Output:
func running
func value
func running
func value
Upvotes: 11
Reputation: 1444
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
Upvotes: 21
Reputation: 2990
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
Upvotes: 27