【问题标题】:How to execute a function once when boolean value changes in python?python - 当布尔值在python中发生变化时如何执行一次函数?
【发布时间】:2017-04-07 07:22:24
【问题描述】:

我正在监视一个外部设备,它在不满足条件时输出布尔值 False,在满足条件时输出布尔值 True。 问题是,布尔值在满足条件后不止一次输出。

这是输出的样子:

False
False
False
False
True
True
False
False
False

所以我想做的是监控这个值并执行一个简单的函数,每次布尔值从 False 变为 True 时只执行一次。我见过其他具有简单“on change”功能的语言,所以我知道它是可能的,而且可能比我想象的要容易得多。

目前我有这个。为了说明这一点,变量“ext_data”用作python脚本正在监控的外部数据。

while True:
    if ext_data == True:
        print("true")
        pass

每次布尔值等于 true 时都会打印“true”,而当它自行重置时,布尔值仍设置为 True,所以当我只想要一个时我会得到多个读数。

感谢任何提供帮助的人!

编辑:

使用 Holdenweb 编写的 EdgeDetector 类更新了代码。

ext_data = True/False  # This returns True or False depending on the state
                       # of the variable. It is constantly monitored and
                       # could change at any moment, which is why I'm 
                       # running the function in a while True loop
def printer():
    print(u'something%s' % serialport.cts)
    post_to_api('cycle_count')

def myfunction():
    return ext_data

test_subject = EdgeDetector(myfunction, printer)

while True:

    test_subject.test()

这仍然会偶尔返回重复的帖子。有人提到,EdgeDetector 类需要将这些数据放在一个数组中才能正常工作,您如何建议将这些数据放入一个数组而不创建无限长的数组?

【问题讨论】:

  • 据我所知,唯一提到将数据存储在数组(实际上是列表)中的人就是你。当您说它“返回重复的帖子”时,您是如何确定的?他们的问题的事实是,除非有一个错误(总是可能的),否则代码不可能检测到边缘,除非首先有一个从高到低的转换(因为从技术上讲,我真的应该称之为 RisingEdgeDetector,但这是假设了解信号的极性)。由于您正在进行轮询,因此您可能会错过短暂的脉冲。

标签: python boolean monitoring onchange


【解决方案1】:

您提出问题的方式并没有说明如何获得外部价值。这必须涉及存储状态信息——特别是最后读取的值。

虽然可以将它存储在全局变量中,但这不是一个好的做法 - 虽然它可能会满足您的即时需求,但如果您尝试基于它创建可重用的软件组件,它将中断同一模块中的某些其他代码决定将同一全局变量用于其他目的的事件。所以上课可能会更令人满意。

编写以下类以接收一个函数,该函数在调用时返回外部变量的值。这作为参数read_signal 传递给类的__init__。第二个参数action 是对象在检测到FalseTrue 转换时应调用的函数。

以这种形式投射它意味着您可以轻松地将其集成到任何程序中,并且如果您需要自己处理许多外部变量,您可以为每个变量创建一个EdgeDetector

class EdgeDetector:
    """Detects False to True transitions on an external signal."""

    def __init__(self, reader, action):
        self.reader = reader
        self.action = action
        self.last_value = reader()    # initialise value

    def test(self):
        new_value = self.reader()
        if new_value and not self.last_value:
            self.action()
        self.last_value = new_value

if __name__ == '__main__':                 # simple self-test
    vlist = [False, False, False, True, True, False, True, True, False, False, False, True]
    vgen = (v for v in vlist)              # generator for value sequence

    def test_reader():                     # generate test sequence
        value = next(vgen)
        print("Read:", value)
        return value

    def printer():
        print("Edge transition detected")

    test_subject = EdgeDetector(test_reader, printer)
    for i in range(len(vlist)-1):
        test_subject.test()

通常您会将此模块导入您的程序,使其更易于重用,并使实现细节远离您的主代码。当作为程序运行时,自检代码会向您显示输入值的顺序以及检测到转换的时间,让您在部署代码之前对代码更有信心。自检的输出为

Read: False
Read: False
Read: False
Read: True
Edge transition detected
Read: True
Read: False
Read: True
Edge transition detected
Read: True
Read: False
Read: False
Read: False
Read: True
Edge transition detected

【讨论】:

  • 这正是我一直在寻找的,每次搜索边缘检测都会返回关于图像处理的精明边缘检测的结果。谢谢这么详细的回复
  • 很高兴为您提供帮助
  • 快速提问,在不存储变量数据的情况下监控实时变量时,您将如何做到这一点?我尝试将活动变量的最后两个值保存到一个列表中,然后在每次列表达到两个值时重写该列表。 IE。该列表将是[False, False],然后它会不断被重写,我会测试它何时等于[False, True],但是我仍然会从中得到双重读数。
  • 也许你在它达到长度 2 后清空它?将新值添加到列表中的正确方法类似于 list = [list[-1], new_value],但您必须将其初始化为至少包含一个值以避免抛出异常访问元素 -1
  • 很抱歉再次打扰您,我编辑了我的原始帖子以更好地阐明我如何获取数据。您如何建议将您的 Class 与不断变化的变量一起使用?更清楚地说,这个变量返回两条线的状态。如果电线没有短接在一起,则返回 false。如果它们已连接,则返回 true。我在一个真正的循环中运行它以不断监视这些电线,因为每次它们短路时我都需要知道。
【解决方案2】:

你可以有一个内部变量,你可以跟踪它(伪代码)

executed = false

if(!executed && output_from_device == true)
    print("true")
    executed = true

但我不知道您的整个设置,因此最好为它创建某种形式的事件处理,而不是幼稚的方法。

【讨论】:

  • executed 应该更新为 false 一旦你的 output_from_devicechange 从 truefalse 像这样:if executed and not output_from_device: executed = false
  • 我已尝试保留建议的内部变量,但无法使其正常工作。我再试一次。因此,通过将“已执行”更新为 false,这允许循环继续进行到下一个实例,对吗?
  • @Dennis 代码应该这样写吗?因为我仍然得到多个读数。 var 是布尔数据,我将 '\n' 用于指示换行符while True:\n if not executed and var:\n print("executed")\n executed = True\n if executed and not var:\n executed = False\n
【解决方案3】:

为什么不做一些简单的事情:

#Input Boolean
inputData = [True,False,False,False,True,True,False]


foo =''

for i in inputData:
   if foo != i:
      print("Yo")
      foo = i

InputData 的第一个元素会触发打印,因为 foo 为空,那么当 foo = True 时,下次当 inputData 元素为 False 时会触发打印……等等……

【讨论】:

  • 因为这是监控实时数据,所以我认为您不能运行 for 循环,因为上限是无限的,对吧?这需要实时监控数据并打印(“yo”),而不是记录数据然后过滤数据
  • 所以这是一种“while True”循环,在循环开始时,您会收到来自其他东西的输入,每次收到这些数据时,您都可以检查我写的“if”条件是否?
猜你喜欢
  • 2019-12-09
  • 2013-06-28
  • 2015-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-29
  • 1970-01-01
  • 2021-12-06
相关资源
最近更新 更多