How to execute a function once when boolean value changes in python?

房东的猫 提交于 2021-01-28 08:31:30

问题


I am monitoring an external device that outputs a boolean value of False when the condition is not met, and a boolean value of True when the condition is met. The problem is, the boolean value is output more than once after the condition is met.

This is what the output looks like:

False
False
False
False
True
True
False
False
False

So what I would like to be able to do is monitor this value and execute a simple function, only once for each time the boolean changes from False to True. I have seen other languages that have a simple "on change" function, so I know its possible and probably a lot easier than I'm making it out to be.

Currently I have this. For the sake of explaining this, the variable "ext_data" is used as the external data that the python script is monitoring.

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

This prints "true" every time the boolean is equal to true, and when it resets itself the boolean is still set to True, so I get multiple readings when I only want one.

Thanks to anyone who helps out!

edit:

Updated code using the EdgeDetector class written by holdenweb.

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()

This still returns occasional duplicate posts. It was mentioned that this data needs to be in an array for the EdgeDetector Class to work properly, how would you suggest putting this data into an array without creating an infinitely long array?


回答1:


The way your question is framed doesn't make it clear how the external value is acquired. This must involve storing state information - specifically, the last value that was read.

While it would be possible to store this in a global variable, this is not good practice - while it may satisfy your immediate needs, if you try to create a re-usable software component based on it, it will break in the event that some other code in the same module decides to use the same global variable for other purposes. So a class might be more satisfactory.

The following class is written to receive a function that, when called, returns the value of the external variable. This is passed to the class's __init__ as parameter read_signal. The second parameter, action, is a function that the object should call when it detects a False to True transition.

Casting it in this form means you can easily integrate it inot any program, and should you fund yourself having to deal with many external variables you can just create an EdgeDetector for each one.

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()

Normally you would import this module into your program, making it easier to re-use and keeping the implementation details well away from your main code. When run as a program the self-test code shows you the sequence of input values and when the transitions are detected, allowing you to have a little more confidence in your code before deploying it. The output of the self-test is

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



回答2:


You could have an internal variable which you keep track off (pseudo code)

executed = false

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

But I don't know your entire setup, so it may be better to create some form of event handling for it rather than a naive approach.




回答3:


Why not somehting simple as :

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


foo =''

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

First element of InputData will trigger print because foo was empty, then as foo = True, the next time the print will be triggered when inputData element will be False ... etc ...



来源:https://stackoverflow.com/questions/43272049/how-to-execute-a-function-once-when-boolean-value-changes-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!