Как вы моделируете состояние с тремя значениями? - PullRequest
2 голосов
/ 18 апреля 2011

У меня есть что-то, что может быть в трех состояниях

(скажем) Открыто, Закрыто, Бег

Я попытаюсь смоделировать его одним из двух способов,

is_open = Boolean(default=False)
is_running = Boolean(default=False)

и Запретить состояние (скажем) is_running = True, is_open = False в коде приложения.

Я тоже могу попробовать

state=Char(choices=("O", "C", "R"))

Один из способов лучше, и есть ли лучший способ сделать это?

Редактировать: я использую Python (и Django).
Изменить 2: После прочтения ответов ниже, я думаю, что я пытаюсь смоделировать Enums в Python (который не имеет их) в форме, которая подходит для сохранения в БД

Ответы [ 6 ]

2 голосов
/ 19 апреля 2011

Самый простой способ справиться с этим в Python - это использовать строковые константы. Мы сделали именно это при добавлении inspect.getgeneratorstate() в Python 3.2. Возможные возвращаемые значения из этой функции:

GEN_CREATED = 'GEN_CREATED'
GEN_RUNNING = 'GEN_RUNNING'
GEN_SUSPENDED = 'GEN_SUSPENDED'
GEN_CLOSED = 'GEN_CLOSED'

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

В Python минимальный выигрыш в использовании целых чисел над строками для ваших констант. Вы немного теряете в скорости сравнения (но не сильно, из-за кэширования хеша и других оптимизаций сравнения строк) и используете немного больше памяти (но не сильно, поскольку ссылки имеют одинаковый размер независимо от типа цели), но значительно упрощаете отладка (поскольку вам не нужно переводить целочисленные коды в значимые имена состояний - вы можете просто отобразить строковые значения).

1 голос
/ 18 апреля 2011

на самом деле вам нужно только два, причина в вашем случае:

closed = ! open

И это зависит от того, может ли быть действительным одновременно только один из трех или более одного, например, открытый и работающий вместе?если бы разрешалось только одно состояние, я бы использовал Перечисления

Так как эта проблема в Python, который не поддерживает Enums, я предлагаю взглянуть на: Как я могу представить«Enum» в Python? Все ответы на первые четыре интересны, но я предпочитаю первый и третий ответы Александра Недельку:

class State:
    OPEN=1
    CLOSED=2
    RUNNING=3

Или ответ Марка Харрисона:

OPEN, CLOSED, RUNNING = range(3)
0 голосов
/ 19 апреля 2011

Это хорошее место для использования "свойств" Python, которые позволяют прозрачно связывать методы get и set с атрибутами объекта.

Таким образом, ваши методы могут управлять желаемым поведением, а ваш код просто должен установить True или False для ваших состояний:

class Machine(object):
    def __init__(self):
        self.open = False
        self._running = False
        self._closed = False

    def get_running(self):
     return self._running

    def set_running(self, val):
        if not self.open and val:
            raise ValueError("Cannot run if it is closed")
        self._running = True

    running = property(get_running, set_running)

    def get_closed(self):
        return self._closed

    def set_closed(self, val):
        if val:
            self.open = False
            self.running = False
        self._closed = val

    closed = property(get_closed, set_closed)

Вставка этого на консоль python позволяет провести быстрый тест-драйв:

>>> m = Machine()
>>> m.open
False
>>> m.running
False
>>> m.running = True
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 12, in set_running
ValueError: Cannot run if it is closed
>>> m.open = True
>>> m.running = True
>>> m.closed
False
>>> m.closed = True
>>> m.open, m.running
(False, True)
>>>
0 голосов
/ 19 апреля 2011

+ 1 для предложений, которые вы, вероятно, хотите перечислить. Поскольку python не поддерживает их, я бы, вероятно, определил класс для его инкапсуляции. Таким образом, вы можете применять правила при обновлении. Как минимум, это даст вам то же поведение, что и перечисление. При необходимости вы также можете контролировать изменения правового состояния, например,

class Widget:
    def __init__(self, state="Closed"):
        self.state=state

    def open(self):
        if self.state == "Closed":
            self.state = "Open"
        elif self.state == "Open":
            pass
        else:
            # do whatever if trying to open in "Running" state...

    def close(self):
        # etc.

class ThingContainingWidget:
    def __init__(self):
        self.widget=Widget()

    def doSomethingThatAffectsWidget(self):
        self.widget.close()
        # etc.

В зависимости от проблемы вам может понадобиться / захотеть переместить логику изменения состояния в охватывающий класс (например, если поведение состояния зависит также и от других атрибутов охватывающего класса). Но я бы, вероятно, оставил базовую проверку (гарантируя, что значение может быть только Open / Closed / Running) в классе Widget.

Давно не делал джанго, но не могу придумать причину, по которой это не сработает.

НТН.

0 голосов
/ 18 апреля 2011

Неуловимое «трибулево» значение.Я видел это где-то раньше.

enum Bool 
{ 
    True, 
    False, 
    FileNotFound 
};

Что такое Истина?- TheDailyWTF

0 голосов
/ 18 апреля 2011

В зависимости от вашего языка, вы можете использовать перечисление:

enum DoohickyState
{
    Open,
    Closed,
    Running
}
...