Properties are a special kind of attribute. Basically, when Python encounters the following code:
spam = SomeObject()
print(spam.eggs)
it looks up eggs in SomeObject1, 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.
Answer from Ethan Furman on Stack OverflowProperties are a special kind of attribute. Basically, when Python encounters the following code:
spam = SomeObject()
print(spam.eggs)
it looks up eggs in SomeObject1, 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.
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
Videos
I have been going through some books on classes to refresh my knowledge of Python, that's when I came across properties? Are they often used in the professional world, if so what are the conditions needed, or its just something that's commonly done like the way its common to use f-strings. Thanks in advance
Whats the difference betweed an attribute and a property?
I'm just trying to get my head around the @property decorator and what the heck it is useful for.
eg, I am working on a script which does a little moving around and renaming of files based on [irrelevant]. I am considering making a File class, like so:
import os
class File:
def __init__(self, f_obj):
self.f_obj = f_obj
self.ext = os.path.splitext(self.f_obj)[1]
self.title = os.path.splitext(self.f_obj)[0]What possible benefit might there be from doing it like this instead?:
class File:
def __init__(self, f_obj):
self.f_obj = f_obj
@property
def ext(self):
return os.path.splitext(self.f_obj)[1]
@property
def title(self):
return os.path.splitext(self.f_obj)[0]
I've looked through a few SO threads and not found a satisfactory answer. They just bang on about getters and setters and people coming from other languages. I have only ever programmed with Python. So I guess a related question might be, is there any point in getters and setters in Python when you can just do instance.attr = value whenever you like.
As a side note, I'm not 100% certain that creating a File class to handle any relative path that isn't a directory is a necessary move. I'm kind of just leaning towards this approach for tidiness and readability; I want to subclass from this based on certain conditions, and the program will really only be operating on instances of the subclass. I'm open to any comments or suggestions on this.
Thanks!
I think your question is wrong.
It's not properties vs attributes. It is properties+attributes vs methods.
Properties and attributes achieve the same thing. The @property decorator adds syntactic sugar to let you call a method as if it was an attribute. That's really it. Methods deserve the important distinction, because their role is different. Methods usually get a verb in their name, (get_this, query_that, set_who, is_what, has_access, etc etc). Methods are for managing your objects to state. It's inappropriate to use methods to access your objects core state. Especially when there's no meaningful verb involved. This is where attributes come in. Attributes represent your objects' "state". @property gives you more control over how you access that state.
There are a couple of seperate issues here - why use properties instead of plain attributes, and why use properties instead of getter/setter methods.
For properties vs attributes, there are a few reasons:
-
API restrictions. Eg. in your example,
extandtitleare modifiable from code using your class. You may instead want these to be read-only to make it clear that these are not meant to be modifiable, which the@propertyversion will do. -
Handling modification. If the value depends on mutable state (eg.
self.f_objmight change in your example) then you'll need to keep those properties synchronised with any such change. -
You may want to do something special on setting, as well as getting. Eg. maybe it's a proxy object and you want changes to be pushed across the network etc.
In general, there's no real problem with using attributes unless you need something like this, since you can always switch to properties at a later point.
For properties versus methods:
-
It's more concise, and communicates that this information is "property-like". For this reason, it's usually a good idea not to have very expensive logic in properties, or to have your getters do stuff like modify state, since it's less expected that accessing an attribute will do such things than calling a method will.
-
You may want to preserve the API with a previous version of your class that used attributes.
It ultimately comes down to a matter of taste here.
Properties are more flexible than attributes, since you can define functions that describe what is supposed to happen when setting, getting or deleting them. If you don't need this additional flexibility, use attributes – they are easier to declare and faster.
In languages like Java, it is usually recommended to always write getters and setters, in order to have the option to replace these functions with more complex versions in the future. This is not necessary in Python, since the client code syntax to access attributes and properties is the same, so you can always choose to use properties later on, without breaking backwards compatibilty.
The point is that the syntax is interchangeable. Always start with attributes. If you find you need additional calculations when accessing an attribute, replace it with a property.
Properties are not intended for providing access to a private attribute. Properties are intended to give you the option of making zero-argument methods accessible as if they were attributes, so that a given "attribute" can be implemented as either a calculation or an actual attribute, without changing the interface of the class.
As such, it's usually not really a question of "better", but rather a design decision with pros and cons that depend on the context.
In this case, whatever this object is supports x.hunger, x.boredom and x.mood. Why not x.mood()? You could, although that exposes permanently in the interface that it is a calculation and is not stored.
If a prior version of the class had a "real" mood attribute, and a required invariant of the object meant that any internal method updating boredom or hunger had to also carefully set mood to be consistent, then introducing the property would be an excellent refactor; the interface stays the same, but the invariant is now guaranteed to always hold, rather than having to be carefully maintained. A whole field of bugs are made impossible to occur.
On the other hand, if mood is expensive to calculate, or has side effects, then it likely would be much better as a normal method. Making it look like an attribute access means that client code programmers will likely think of it as an attribute access, which is cheap and non-destructive; this would be a rich source of bugs or performance problems.
It's just a matter of taste.
A property is used where an access is rather cheap, such as just querying a "private" attribute, or a simple calculation.
A method is used where a rather "complicated" process takes place and this process is the main thing.
People are used to using getter and setter methods, but the tendency is used for useing properties more and more.
Take, as an example, the Serial class of pyserial. It has - as a heritage - methods such as getBaudRate() and setBaudRate(), but recommends to use baudrate as a reading and writing property for querying and setting the baud rate.
Suppose I had the class `vehicle` which represents a motor vehicle. Suppose the horsepower of the vehicle was not passed as an inputs but, with some detailed calculation, could be calculated from the other properties of the vehicle class. Would it be better to add `horsepower` as a property of the `vehicle` class, or as a method?
As a property, this might look something like this:
class Vehicle:
def __init__(self, args):
# Set args
self._horsepower = None
@property
def horsepower(self):
if self._horsepower is None:
self._horsepower = calculate_horsepower()
return self._horsepowerAs a method, it may look like this:
class Vehicle:
def __init__(self, args):
# Set args
def calculate_horsepower(self):
# Calculate horsepower of instance vehicleWhich of the above is preferable?
In reality, horsepower is a property of a vehicle. However, if significant processing is required to calculate it then I'm not sure if it feels right to have it as a property of the `vehicle` class.