[Fixed]-What's the difference between property and class method?

15👍

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.

3👍

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.

👤geckon

Leave a comment