By using the @property
decorator, Python has completely eliminated the need for getters and setters on object properties (some might say 'attributes'). This makes code much simpler, while maintaining the extensibility when things do need to get more complex.
I was wondering what the Pythonic approach to the following kind of method is, though. Say I have the following class:
class A(object):
def is_winner(self):
return True # typically a more arcane method to determine the answer
Such methods typically take no arguments, and have no side effects. One might call these predicates. And given their name, they often closely resemble something one might also have stored as a property.
I am inclined to add a @property
decorator to the above, in order to be able to call it as an object property (i.e. foo.is_winner
), but I was wondering if this is the standard thing to do. At first glance, I could not find any documentation on this subject. Is there a common standard for this situation?
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.
The simplest way to get a list of methods of any object is to use the help() command. It will list out all the available/important methods associated with that object.
__get__(self, obj, type=None) : This attribute is called when you want to retrieve the information (value = obj. attr) , and whatever it returns is what will be given to the code that requested the attribute's value. gfg.
One of the easiest ways to access a Python object's attributes is the dir() function. This function is built-in directly into Python, so there's no need to import any libraries.
It seems that the general consensus is that attributes are generally seen as being instant and next-to-free to use, so if the computation being decorated as a @property is expensive, it's probably best to either cache the outcome for repeated use (@Martijn Pieters) or to leave it as a method, as methods are generally expected to take more time than attribute lookups. PEP 8 notes specifically:
Note 2: Try to keep the functional behavior side-effect free, although side-effects such as caching are generally fine.
Note 3: Avoid using properties for computationally expensive operations; the attribute notation makes the caller believe that access is (relatively) cheap.
One particular use case of the @property decorator is to add some behavior to a class without requiring that users of the class change from foo.bar
references to foo.bar()
calls -- for example, if you wanted to count the number of times that an attribute was referenced, you could convert the attribute into a @property where the decorated method manipulates some state before returning the requested data.
Here is an example of the original class:
class Cat(object):
def __init__(self, name):
self.name = name
# In user code
baxter = Cat('Baxter')
print(baxter.name) # => Baxter
With the @property decorator, we can now add some under-the-hood machinery without affecting the user code:
class Cat(object):
def __init__(self, name):
self._name = name
self._name_access_count = 0
@property
def name(self):
self._name_access_count += 1
return self._name
# User code remains unchanged
baxter = Cat('Baxter')
print(baxter.name) # => Baxter
# Also have information available about the number of times baxter's name was accessed
print(baxter._name_access_count) # => 1
baxter.name # => 'Baxter'
print(baxter._name_access_count) # => 2
This treatment of the @property decorator has been mentioned in some blog posts(1, 2) as one of the main use cases -- allowing us to initially write the simplest code possible, and then later on switch over to @propery-decorated methods when we need the functionality.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With