Funktion beenden

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Hallo, ich möchte ein Programm bauen, welches bei bestimmten Ereignissen eine Funktion auslöst, die jeweilige Funktion soll per while-True-Schleife so lange gehen bis ein anderes Ereignis auftritt. das Ereignis ist eine Fernbedienung.

Jetzt weiß ich aber nicht, wie ich dann so eine Funktion mit Endlosschleife beenden kann.
Könnte mir jemand einen Tipp geben?

Grüße
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Mal ähnlich allgemein gehalten wie deine Frage:
Innerhalb der Endlosschleife prüfst du, ob das Ereignis aufgetreten ist, und beendest die Schleife dann, bzw. reagierst auf das Ereignis, bevor du sie wieder startest.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ja die Frage war bewusst allgemein gehalten, weil mir es um das Prinzip geht.
In der Schleiße wird etwas endlos ausgeführt.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann muss es eben einen Abbruchbedingung geben, die in der schleifenbedingung oder innerhalb der Schleife geprüft wird, und dann verlässt man die Schleife.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@egon11: Eine Endlosschleife kann man mit ``break``, ``return``, oder einer Ausnahme verlassen. ``return`` nur falls sich die Schleife innerhalb einer Funktion oder Methode befindet. Und dann wäre da noch ``yield`` womit man eine (Generator-)Funktion/Methode anhalten kann, und sich an anderer Stelle entscheiden kann ob man sie irgendwann noch mal weiterlaufen lässt oder nicht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Das ist event-basierte Programmierung: Du hast eine Hauptschleife die Events erkennt und eventuell auch Status-Informationen speichert. Anhand dessen rufst du aus der Hauptschleife immer die Funktion auf, die zum aktuellen Status passt. Du lagerst also die Endlosschleife aus der Funktion aus.
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

egon11 hat geschrieben: Freitag 3. März 2023, 17:15 die Frage war bewusst allgemein gehalten, weil mir es um das Prinzip geht.
In der Schleiße wird etwas endlos ausgeführt.
Dennoch wäre ein Beispiel in Code recht hilfreich, um das allgemeine Prinzip abzubilden.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Also es geht um eine event-basierte-Schleife.

Genau gesagt geht es um den folgenden Teil:

Code: Alles auswählen

import time
from machine import Pin
from ir_rx import NEC_16
from time import sleep


wert = {0x45:"1", 0x46:"2"}

def callback(data, addr, ctrl):
    if data > 0:  # NEC protocol sends repeat codes.
        #print('Data {:05x} Addr {:04x}'.format(data, addr))
       # print(ir_data)#
       # print("huhu")
       if wert[data] == "1":
           eins()
        if wert[data] == "2":
            zwei()

ir = NEC_16(Pin(16, Pin.IN), callback)

def eins():
    while True:
        print("eins")
        sleep(0.5)
    
def zwei():
    while True:
        print("zwei")
        sleep(0.5)
Die Methode ist event-basiert.

Nun möchte ich, je nachdem welche Taste gedrückt wurde folgende Methode aufrufen, um sie bei der nächsten Taste die gedrückt wurde wieder anzuhalten.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das geht so gar nicht, weil der `callback` ziemlich sicher nur kurz etwas tun darf, und nicht in einer Endlosschleife enden darf.

Das Beispiel könnte man so ausdrücken (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
from functools import partial
from queue import Empty, Queue

from ir_rx import NEC_16
from machine import Pin

DATA_TO_TEXT = {0x45: "eins", 0x46: "zwei"}


def callback(queue, data, _addr, _ctrl):
    if data > 0:  # NEC protocol sends repeat codes.
        queue.put(DATA_TO_TEXT[data])


def main():
    queue = Queue()
    _ir = NEC_16(Pin(16, Pin.IN), partial(callback, queue))
    text = None
    while True:
        if text is not None:
            print(text)

        try:
            text = queue.get(timeout=0.5)
        except Empty:
            pass  # Intentionally ignored.


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ich wollte den code gerade versuchen, aber leider bietet Micropython mir kein queue an
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Micropython kennt asyncio für solche Zwecke. Eine englische Einführung findet sich zB hier: https://github.com/peterhinch/micropyth ... UTORIAL.md

Kann man sicher mit Deepl auf Deutsch ausreichend gut übersetzen.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das hier zb ist ein ziemlich nahes Beispiel: https://github.com/peterhinch/micropyth ... ncellation
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Wenn du mit Events arbeitest, dann kannst du kein Sleep benutzen, weil sonst das ganze Programm anhält.

Die Hauptschleife darf aber nicht anhalten, sondern muss kontinuierlich prüfen, ob neue Events aufgetreten sind.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Jetzt habe ich folgen (funktionierenden) Code

Code: Alles auswählen

wert = {0x45:"1", 0x46:"2"}

async def test1():
    while True:
        print("methode 1 zum ausfuhren")
        await asyncio.sleep(1)
        
async def test2():
    while True:
        print("methode 2 zum ausfuhren")
        await asyncio.sleep(1)
    
async def start(x):
    print("übergebener Wert " + x)
    
    if x == "1":
        task1 = asyncio.create_task(test1())
        await asyncio.sleep(3)
        print("beenden")
        task1.cancel()
    if x == "2":
        task2 = asyncio.create_task(test2())
        await asyncio.sleep(3)
        print("beenden")
        task2.cancel()

def callback(data, addr, ctrl):
    if data > 0:  # NEC protocol sends repeat codes.
        print('Data {:05x} Addr {:04x}'.format(data, addr))
        print(wert[data])
      
        asyncio.run(start(wert[data]))
    
if __name__ == "__main__":
    ir = NEC_16(Pin(16, Pin.IN), callback)
Sie macht erstmal genau das, was sie soll.
Jetzt muss ich noch in der Methode start() einbauen, welche Methode gerade ausgeführt wird oder nicht. Wenn ich das überprüft habe muss ich jene erstmal beenden und dann eine andere starten.

Wenn ich dann aber in der Methode start() `await asyncio.sleep(3)` und ` task2.cancel()` weg lasse, dann werden die Methoden nur 1x ausgeführt.

Das heißt, ich muss es irgendwie schaffen, dass sie dauerhaft laufen, bis man wider etwas drückt, dann die laufende Methode beenden und eine andere startet.
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Ich würde da nicht async benutzen. Wie wäre es denn so?

Code: Alles auswählen

def task_1():
        print("methode 1 zum ausfuhren")
        
def task_2():
        print("methode 2 zum ausfuhren")
    
def start(x):
    print("übergebener Wert " + x)
    
    if x == "1":
        current_task = task_1
    if x == "2":
        current_task = task_2
    
    current_task()
    sleep(0.5)
    x = neues_x_bestimmen()
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Naja es geht ja darum, das die Methoden task_1 und task_2 eine Endlosschleife beinhalten, und dann irgendwann mal abgebrochen werden sollen, wenn sich x ändert.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Geht. Mit. Asyncio. Weil man da tasks cancels kann. Schon probiert?
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ja habe schon getestet, aber die Endlosschleifen laufen nicht weiter, siehe mein Code oben, der Code funktioniert so, aber sobald ich task.cancel() raus nehme, dann funktioniert es nicht mehr.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du kannst einen task dazu benutzen auf ein Ereignis aus dem Interrupt zu warten, und der canceled dann den laufenden & startet den neuen, bevor er wieder wartet auf eine Eingabe.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

OK, könntest du das anhand von einen kleinen Code zeigen? Ich weiß gerade nicht wie ich das umsetzen sollte.
Antworten