Идиоматический питон - свойство или метод?
У меня есть класс модели 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
Просто помните, что он "кэширует" результаты, поэтому первое выполнение выполняет расчет, но последующее использование существующих результатов.