Zählen lassen

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.
Antworten
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

Ein hier häufig gelesener Satz lautet: "Nicht selber zählen, zählen lassen"

Wie zähle ich zB die Anzahl einer aufgerufenen Funktion ohne globale Variablen? Hier habe ich es so gelöst:

Code: Alles auswählen

def counter(func):
    @wraps(func)
    def tmp(*args, **kwargs):
        tmp.count += 1
        return func(*args, **kwargs
Ein anderes Beispiel ist dieser Thread:

Code: Alles auswählen

def motion_detected(channel):
    print('Motion detected Nr.: ')


def main():
    GPIO.add_event_detect(PIR_PIN, GPIO.RISING, callback=motion_detected)
    # print Anzahl Aufrufe von motion_detected()
    
if __name__ == '__main__':
    main()
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Leider kann ich nicht mehr editieren:

Ich meine, wie kann so etwas vermieden werden im Kontext zum obigen Beispiel:

Code: Alles auswählen

count = 0

def motion_detected(channel):
    global count
    count = count + 1
    print(count)
BlackJack

@lackschuh: Na da würde doch der Dekorator funktionieren‽

Wenn man nicht *einen* Zähler fest an die Funktion binden möchte, kann man so etwas machen:

Code: Alles auswählen

def motion_detected(channel):
    print('Motion detected Nr.: ')


class CallCounter(object):
    def __init__(self, function):
        self.function = function
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        self.function(*args, **kwargs)


def main():
    counted_motion_detected = CallCounter(motion_detected)
    GPIO.add_event_detect(PIR_PIN, GPIO.RISING, callback=counted_motion_detected)
    print(counted_motion_detected.count)
So könnte man dann auch die gleiche Funktion für unabhängige Bewegungssensoren verwenden.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

@BlackJack

Danke, so könnte ich auf den Dekorator verzichten (so wie du es im anderen Thread geschrieben hast) und die Klasse noch mit anderen Attributen vollstopfen(?)
BlackJack

@lackschuh: Die Formulierung klingt ja nicht gut. :-) Man könnte statt solcher generischen Sachen auch eine Klasse schreiben die einen Bewegungsensor modelliert und die dann auch gleich Thread-sicher machen. Also zum Beispiel so etwas in dieser Richtung:

Code: Alles auswählen

class MotionDetector(object):

    def __init__(self, pin, callback=None):
        self.pin = pin
        self.callback = callback
        self.lock = threading.Lock()
        self.count = 0
        GPIO.add_event_detect(
            self.pin, GPIO.RISING, callback=self.motion_detected
        )

    def motion_detected(self, channel):
        with self.lock:
            self.count += 1
        if self.callback:
            self.callback(channel)

    def get_and_reset_count(self):
        with self.lock :
            result = self.count
            self.count = 0
        return result


def main():
    motion_detector = MotionDetector(PIR_PIN)
    while True:
        time.sleep(1)
        print(motion_detector.get_and_reset_count())
Antworten