【问题标题】:Moving from one enum state to the next and cycling through从一个枚举状态移动到下一个枚举状态并循环遍历
【发布时间】:2023-03-31 13:27:01
【问题描述】:

我只有具有 3 种模式 ledOn、ledBlink、ledOFF 的枚举器,并且我有一个可变模式来跟踪特定对象的模式。因此,例如,我有一个 LED 以模式 ledOn 启动,例如,我想在 5 秒后移动到下一个元素,该元素将是 ledBlink,然后到 ledOFF,然后循环到 ledON 是否有一种简单的方法来实现这样的事情?

import time
from threading import Thread
from enum import Enum

class ledController(Thread):
    ledModes = Enum('ledModes', 'ledON ledBlink ledOFF')
    def __init__(self, GPIOID, state=False, blinkDuration=2, mode=ledModes.ledON):
        self.GPIOID = GPIOID
        self.state = state
        self.blinkDuration = blinkDuration
        self.mode = mode
        self.blinked = False
        Thread.__init__(self)
    def run(self):
        if(self.mode == self.ledModes.ledON):
            self.ledON()
        if(self.mode == self.ledModes.ledBlink):
            self.ledBlink()
        if(self.mode == self.ledModes.ledOFF):
            self.ledOFF()
        time.sleep(self.blinkDuration)
        self.mode.next()
    def ledSwitch(self):
        self.state = not self.state
        print(self.ledDetails())
    def ledON(self):
        self.state = True
        print(self.ledDetails())
    def ledOFF(self):
        self.state = False
        print(self.ledDetails())
    def ledBlink(self, duration):
        self.ledON()
        print(self.ledDetails())
        time.sleep(self.Blinkduration)
        self.ledOFF()
        print(self.ledDetails())
        time.sleep(self.Blinkduration)
    def ledDetails(self):
        return "Thread: "+self.getName()+", LED: "+str(self.GPIOID)+", State: "+str(self.state)+", Mode: "+str(self.mode.name)+", Blink duration: "+str(self.blinkDuration)

redLED = ledController(17, blinkDuration = 3)
blueLED = ledController(18, mode = ledController.ledModes.ledOFF)

redLED.setName('1')
blueLED.setName('2')

redLED.start()
blueLED.start()

redLED.join()
blueLED.join()

【问题讨论】:

    标签: python enums


    【解决方案1】:

    我只会使用 itertools.cycle 而不是你的枚举:

    >>> from itertools import cycle
    >>> ledModes = cycle(['ledON', 'ledBlink', 'LedOFF'])
    >>> first = next(ledModes)
    >>> second = next(ledModes)
    >>> third = next(ledModes)
    >>> fourth = next(ledModes)
    >>> 
    >>> first
    'ledON'
    >>> second
    'ledBlink'
    >>> third
    'LedOFF'
    >>> fourth
    'ledON'
    >>> 
    

    仅供参考,您可以使用next(ledModes)ledModes.next(),两者都在做同样的事情。

    编辑:你可以使用这样的东西,作为你的类的方法:

    from itertools import cycle
    
    def initialize_cycle(start_mode):
        states = ['ledON', 'ledBlink', 'ledOFF']
    
        if start_mode not in states:
            raise ValueError('start_mode invalid')
    
        iterable = cycle(states)
        for _ in states[:states.index(start_mode)]:
            iterable.next()
    
        return iterable
    
    test1 = initialize_cycle('ledON')
    test2 = initialize_cycle('ledOFF')
    test3 = initialize_cycle('ledBlink')
    
    # validation
    for test in test1, test2, test3:
        for _ in range(5):
            print test.next()
        print '-' * 20
    

    输出:

    $ python cycle.py
    ledON
    ledBlink
    ledOFF
    ledON
    ledBlink
    --------------------
    ledOFF
    ledON
    ledBlink
    ledOFF
    ledON
    --------------------
    ledBlink
    ledOFF
    ledON
    ledBlink
    ledOFF
    --------------------
    

    【讨论】:

    • 我如何将此值分配给例如模式,例如模式 = ledModes?我的意思是我不想总是从 ledON 开始循环,我希望它成为用户选择的第一个状态
    • 我在答案中添加了一个编辑,只是一个想法,也许它可以提供帮助。
    【解决方案2】:

    对当前代码最简单的修复方法是:

    • 更改您的 run 方法,然后
    • 添加next_mode方法:

    像这样:

    def run(self):
        while True:
            set_mode = getattr(self, self.mode)
            set_mode()
            time.sleep(self.blinkDuration)
            self.next_mode()
    
    def next_mode(self):
        self.mode = {
                self.ledModes.ledON: self.ledModes.ledBlink,
                self.ledModes.ledBlink: self.ledModes.ledOFF,
                self.ledModes.ledOff: self.ledModes.ledOn,
                }[self.mode]
    

    【讨论】:

      【解决方案3】:

      可能有点矫枉过正:

      import itertools
      
      class EnumCycler(object):
          def __init__(self, enum, start_at=None):
              self.enum = enum
              self.members = list(enum.__members__.values())
              self.start_at = self.members[0] if start_at is None else start_at
              self.cycles = 0
      
          def __iter__(self):
              cycle = itertools.cycle(self.members)
              sanity_check = len(self.members)
              for value in cycle:
                  if sanity_check:
                      if value != self.start_at:
                          sanity_check -= 1
                          continue
                      sanity_check = 0
                  self.cycles += 1
                  yield value
      

      然后:

      >>> mode = Enum('ledModes', 'ledON ledBlink ledOFF')
      >>> led_mode_cycler = EnumCycler(mode, start_at=mode.ledOFF)
      >>> for value in led_mode_cycler:
      ...     print(led_mode_cycler.cycles, value)
      ...     if led_mode_cycler.cycles >= 10: break  # infinite loop if we never break off
      1 ledModes.ledOFF
      2 ledModes.ledON
      3 ledModes.ledBlink
      4 ledModes.ledOFF
      5 ledModes.ledON
      6 ledModes.ledBlink
      7 ledModes.ledOFF
      8 ledModes.ledON
      9 ledModes.ledBlink
      10 ledModes.ledOFF
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多