Hugo Rodger-Brown
Hugo Rodger-Brown

Reputation: 11582

Idiomatic python - property or method?

I have a django model class that maintains state as a simple property. I have added a couple of helper properties to the class to access aggregate states - e.g. is_live returns false if the state is any one of ['closed', 'expired', 'deleted'] etc.

As a result of this my model has a collection of is_ properties, that do very simple lookups on internal properties of the object.

I now want to add a new property, is_complete - which is semantically the same as all the other properties - a boolean check on the state of the object - however, this check involves loading up dependent (one-to-many) child objects, checking their state and reporting back based on the results - i.e. this property actually does some (more than one) database query, and processes the results.

So, is it still valid to model as a property (using the @property decorator), or should I instead forego the decorator and leave it as a method?

Pro of using a property is that it's semantically consistent with all the other is_ properties.

Pro of using a method is that it indicates to other developers that this is something that has a more complex implementation, and so should be used sparingly (i.e. not inside a for.. loop).

from django.db import models

class MyModel(models.Model):

    state = CharField(default='new')

    @property
    def is_open(self):
        # this is a simple lookup, so makes sense as a property
        return self.state in ['new', 'open', 'sent']

    def is_complete(self):
        # this is a complex database activity, but semantically correct
        related_objects = self.do_complicated_database_lookup()
        return len(related_objects)==0

EDIT: I come from a .NET background originally, where the split is admirably defined by Jeff Atwood as

"if there's any chance at all that code could spawn an hourglass, it definitely should be a method."

EDIT 2: slight update to the question - would it be a problem to have it as a method, called is_complete, so that there are mixed properties and methods with similar names - or is that just confusing?

So - it would look something like this:

>>> m = MyModel()
>>> m.is_live
True
>>> m.is_complete()
False

Upvotes: 15

Views: 2538

Answers (1)

Tadeck
Tadeck

Reputation: 137350

It is okay to do that, especially if you will use the following pattern:

class SomeClass(models.Model):
    @property
    def is_complete(self):
        if not hasattr(self, '_is_complete'):
            related_objects = self.do_complicated_database_lookup()
            self._is_complete = len(related_objects) == 0
        return self._is_complete

Just remember that it "caches" the results, so first execution does calculation, but subsequent use existing results.

Upvotes: 9

Related Questions