【问题标题】:How do you model a state with three values?您如何为具有三个值的状态建模?
【发布时间】:2011-08-07 21:33:49
【问题描述】:

我有一个可以处于三种状态的东西

(比如说)打开、关闭、运行

我将尝试通过两种方式之一对其进行建模,

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:阅读下面的答案后,我想我正在尝试以适合持久保存到 DB 的形式模拟 Python 中的枚举(没有它们)

【问题讨论】:

  • 您使用哪种编程语言?可用的语言结构可能会对首选的选择产生影响...

标签: python data-modeling models modeling


【解决方案1】:

根据您的语言,您可以使用枚举:

enum DoohickyState
{
    Open,
    Closed,
    Running
}

【讨论】:

    【解决方案2】:

    实际上你只需要两个,因为你的情况:

    closed = ! open
    

    这取决于是否只有三个中的一个或实际上不止一个可以同时有效,例如打开并一起运行?如果一次只允许一个状态,我会使用Enumerations

    由于这个问题出现在不支持枚举的 Python 中,我建议看一下:How can I represent an 'Enum' in Python? 第四个答案都很有趣,但我更喜欢第一个和第三个答案,来自 Alexandru Nedelcu:

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

    或者 Mark Harrison 的回答是这样的:

    OPEN, CLOSED, RUNNING = range(3)
    

    【讨论】:

    • 认为你错了:OP 可能有一个状态机:Closed->Open->Running。您不能只删除其中一种状态。
    • 我没有放弃任何东西,但他选择的例子有点令人困惑,考虑一下套接字!在这种情况下,我猜想运行包括打开,所以我只是说答案取决于状态彼此之间的隔离程度。一次只针对 1 个状态,我建议使用枚举。
    • 外径我想我正在尝试以适合持久保存到数据库的形式模拟 Python 中的枚举(其中没有枚举)
    • @agiliq 我添加了 Python 标签,因为这是非常相关的信息,请参阅此线程:stackoverflow.com/questions/36932/…
    【解决方案3】:

    难以捉摸的“Tri-boolean”值。我以前在某个地方见过这个。

    enum Bool 
    { 
        True, 
        False, 
        FileNotFound 
    };
    

    What is Truth? - TheDailyWTF

    【讨论】:

      【解决方案4】:

      +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.
      

      根据问题,您可能需要/想要将状态更改逻辑移动到封闭类(例如,如果状态行为也依赖于封闭类的其他属性)。但我可能会在 Widget 类中保留基本验证(确保值只能是 Open/Closed/Running)。

      有一段时间没有做任何 django 了,但想不出为什么这不起作用。

      第一次。

      【讨论】:

        【解决方案5】:

        这是一个使用 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)
        >>>
        

        【讨论】:

          【解决方案6】:

          在 Python 中处理此问题的最简单方法是使用字符串常量。我们在将inspect.getgeneratorstate() 添加到 Python 3.2 时正是这样做的。该函数的可能返回值是:

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

          创建一个简单的类作为常量的命名空间是另一种常见的选择(但该类的属性仍然应该是字符串而不是整数)。

          在 Python 中,使用整数而不是字符串作为常量的增益很小。您在比较速度上损失了一点点(但不多,由于哈希缓存和其他字符串比较优化)并使用了更多的内存(但不多,因为无论目标类型如何,引用都是相同的大小),但大大简化了调试(因为您不需要将整数代码转换为有意义的状态名称 - 您可以只显示字符串值)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-09-13
            • 2014-03-18
            • 2018-11-14
            • 1970-01-01
            • 2013-05-16
            相关资源
            最近更新 更多