Reputation: 433
What's the difference between a class property and a class method? As I understand it, property is calculated when an object is created. And method makes calculations when I call it.
Is there any other difference than that?
For example, I have a property
in my class Product()
:
@property
def total_ammount_in_store(self):
consignments = self.product.package.consignments
total_ammount = 0
for consignment in consignments:
total_ammount += consignment.package_ammount
When I render some page, I pass some products. For example:
{'products':Product.objects.filter(expiration_data < datetime.now())
I don't need to calculate total_ammount_in_store
every time I get an instance of Product
. What if I just need to calculate it when I call it in a template: {{product.total_ammount_in_store}}? Is it possible?
Is method also calculated when the object is created?
Upvotes: 14
Views: 14751
Reputation: 308789
The property is called each time you access product.total_ammount_in_store
, not at the time when the product is created.
Therefore including {{ product.total_ammount_in_store }}
in your template will do the right thing.
By using the property decorator, you can access product.total_ammount_in_store
instead of product.total_ammount_in_store()
if it was an instance method. In the Django template language, this difference is not so apparent, because Django will call the method automatically in the template.
Don't confuse an instance method with a class method, which is quite different. A class method belongs to your class Product
, not an individual instance product
. You don't have access to instance variables e.g. self.package
when you call a class method.
Upvotes: 17
Reputation: 8754
The @property
decorator can be used to implement a getter for your class' instance variable (in your case it would be self.total_ammount_in_store
). Every time you call some_product.total_ammount_in_store
, the decorated method is executed. It wouldn't make sense to execute it only when a new object is created - you want to get current amount in store, don't you?
More reading on @property
is in Python documentation (it's a Python's construct, not Django's):
https://docs.python.org/2/library/functions.html#property
As for class methods, they are something completely different. As the name suggests, they're tied to classes, not instances. Therefore, no instance is needed to call a class method, but also you can't use any instance variables in class methods (because they are tied to a particular instance).
To the Django related part of your question...
If you include {{ some_product.total_ammount_in_store }}
in your template, then every time the page is displayed, the total amount in store is obtained from the some_product
instance. Which means that the decorated total_ammount_in_store
getter is called.
If for example the total amount in store isn't changed during the product's life, you can calculate the amount in __init__
method and then only return the value. If the total amount can change you can do it as well but you will need to ensure that the amount is re-calculated every time it should be changed - e.g. by calling a method. Like this:
class Product(object):
def __init__(self):
# ...
# other initialization
# ...
self.recalculate_amount()
def recalculate_amount(self):
consignments = self.product.package.consignments
self._total_amount = 0
for consignment in consignments:
self._total_amount += consignment.package_amount
@property
def total_amount(self):
"""Get the current total amount in store."""
return self._total_amount
Then the getter is still called every time you call some_product.total_ammount_in_store
(e.g. in your Django template), but it will not calculate the amount every time - it will use the stored amount instead.
Upvotes: 3