Обработка свойств класса с неизвестным значением по умолчанию в Python - PullRequest
0 голосов
/ 01 ноября 2018

У меня есть класс, подобный следующему:

class Invoice
    def __init__(self, invoice_id):
        self.invoice_id = invoice_id
        self._amount = None

    @property
    def amount(self):
        return self._amount

    @amount.setter
    def amount(self, amount):
        self._amount = amount

В приведенном выше примере, всякий раз, когда я пытался бы получить сумму счета-фактуры без указания ее значения, я получал None, например:

invoice = Invoice(invoice_id='asdf234')
invoice.amount
>> None

Но в этой ситуации None не является правильным значением по умолчанию для суммы. Я должен быть в состоянии различить значение суммы, так как значение «Нет» и значение суммы не были установлены вообще. Итак, вопрос следующий:

  1. Как мы обрабатываем случаи, когда свойство класса не имеет правильного значения по умолчанию? В приведенном выше примере, если я удаляю self._amount = None из init, я получу AttributeError для self._amount, а self.amount вернет допустимое значение только после того, как я вызову invoice.amount = 5. Это правильный способ справиться с этим? Но это также приводит к несогласованности в состоянии объекта, поскольку приложение будет изменять свойства экземпляра во время выполнения.
  2. Я сохранил количество в качестве свойства для счета-фактуры для лучшего понимания и удобочитаемости счета-фактуры и его атрибутов. Должны ли свойства класса использоваться только тогда, когда нам известны его значения init / default?

Ответы [ 3 ]

0 голосов
/ 01 ноября 2018

Вы можете создать статический класс и использовать его, чтобы определить, было ли значение установлено вообще.

class AmountNotSet(object):
    pass


class Invoice(object):
    def __init__(self, invoice_id):
        self.invoice_id = invoice_id
        self._amount = AmountNotSet
    # ...etc...

Затем вы можете проверить, выставлен счет-фактура или нет:

invoice1 = Invoice(1)
invoice2 = Invoice(2)
invoice2.amount = None

invoice1.amount is AmountNotSet  # => True
invoice2.amount is None          # => True
0 голосов
/ 01 ноября 2018

None обычно используется для отсутствия значения, но иногда вам нужно, чтобы оно действительно было допустимым значением. Если вы хотите различать None и неустановленное значение, просто определите для этого свой собственный синглтон.

class Undefined:
    __str__ = __repr__ = lambda self: "Undefined"

Undefined = Undefined()

class Invoice
    def __init__(self, invoice_id):
        self.invoice_id = invoice_id
        self._amount = Undefined

    @property
    def amount(self):
        return self._amount

    @amount.setter
    def amount(self, amount):
        if amount is Undefined:
            raise ValueError("amount must be an actual value")
        self._amount = amount

Конечно, теперь вам может понадобиться проверить на Undefined в других методах, чтобы убедиться, что они не используются до правильной инициализации экземпляра. Лучшим подходом может быть установка атрибута во время инициализации и требование передачи его значения в __init__(). Таким образом, вы не будете иметь Invoice в недопустимом (не полностью инициализированном) состоянии. Кто-то все еще может установить _amount на недопустимое значение, но он просто получит проблему, о которой он просил. Мы все здесь взрослые.

0 голосов
/ 01 ноября 2018

Не используйте property в этом случае. Ваши геттеры и сеттеры ничего не делают, кроме возврата и установки значения . Просто используйте нормальный атрибут . Если позже вы захотите контролировать доступ, вы можете просто добавить это свойство позже, не изменяя интерфейс вашего класса!

Что касается работы с ненулевыми значениями, просто создайте свой собственный объект для представления значения, которое никогда не было установлено. Это может быть так просто, как:

>>> NOT_SET = object()
>>> class Invoice:
...     def __init__(self, invoice_id):
...         self.invoice_id = invoice_id
...         self.amount = NOT_SET
...
>>> inv = Invoice(42)
>>> if inv.amount is NOT_SET:
...     inv.amount = 1
...

Вы также можете использовать enum, если хотите улучшить поддержку при наборе текста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...