Идиоматический питон - свойство или метод?

У меня есть класс модели django, который поддерживает состояние как простое свойство. Я добавил несколько вспомогательных свойств классу для доступа к агрегатным состояниям - например. is_live возвращает false, если состояние является любым из ['closed', 'expired', 'deleted'] и т.д.

В результате этого моя модель имеет набор свойств is_, которые выполняют очень простой поиск по внутренним свойствам объекта.

Теперь я хочу добавить новое свойство is_complete, которое семантически такое же, как и все остальные свойства, - логическая проверка состояния объекта. Однако эта проверка включает загрузку зависимых (однонаправленный) многие) дочерние объекты, проверяющие их состояние и отчетность на основе результатов - то есть это свойство фактически выполняет некоторые (более одного) запроса базы данных и обрабатывает результаты.

Итак, допустимо ли это моделировать как свойство (с помощью декоратора @property), или я должен вместо этого отказаться от декоратора и оставить его как метод?

Pro использования свойства состоит в том, что он семантически согласуется со всеми другими свойствами is_.

Pro использования метода состоит в том, что он указывает другим разработчикам, что это то, что имеет более сложную реализацию, и поэтому должно использоваться экономно (т.е. не внутри цикла for..).

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: я исхожу из .NET-фона изначально, где раскол превосходно определен Джеффом Этвудом как

", если какой-либо шанс, что этот код может порождать песочные часы, это определенно должен быть метод.

РЕДАКТИРОВАТЬ 2: небольшое обновление к вопросу - было бы проблемой иметь его как метод, называемый is_complete, так что существуют смешанные свойства и методы с похожими именами - или это просто запутывает?

Итак - это выглядело бы примерно так:

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

Ответы

Ответ 1

Это нормально, особенно если вы будете использовать следующий шаблон:

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

Просто помните, что он "кэширует" результаты, поэтому первое выполнение выполняет расчет, но последующее использование существующих результатов.