ein (Klassen-)Funktion alle x Sekunden/Minuten ausführen

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
der_Angler
User
Beiträge: 25
Registriert: Montag 28. Januar 2013, 00:48

Nabend,

ich bastle an einem kleinen Script mit welchem ich diverse Sensoren übers Tablet auslesen kann.
Dafür nutze ich einen Socket-Server.

Jetzt würde ich gerne zusätzlich eine Art "Zeitschaltuhr" einbauen.
Im Detail soll eine Klassen-Funktion (zum auslesen der CPU-Temperatur) alle 30 Sekunden ausgeführt werden.

Bisher verlaufen aber alle Versuche erfolglos. Das Problem scheint hier der gleichzeitig Betrieb des Socket-Servers zu sein.

Ich habe deshalb verschiedene Möglichkeiten versucht, bisher alle ohne Erfolg.

Hier mein Code

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

logPath = "/var/log/raspi_server.log"
serverPort = 54321

import datetime
import asyncore
import socket
import select
import commands
import schedule
import time
from datetime import timedelta


class cls_Raspi_Temp:
    temp_cpu = 0
    temp_gpu = 0
    
    def __init__(self):
        self.read()
        
    def read(self):
        tempFile = open( "/sys/class/thermal/thermal_zone0/temp" )
        cpu_temp = tempFile.read()
        tempFile.close()
        self.temp_cpu = float(cpu_temp)/1000
        gpu_temp = commands.getoutput( '/opt/vc/bin/vcgencmd measure_temp' ).replace( 'temp=', '' ).replace( '\'C', '' )
        self.temp_gpu = float(gpu_temp)
        print(str(get_systemzeit()) + " : CPU Temperatur " + str(self.temp_cpu) + " °C")
        print(str(get_systemzeit()) + " : GPU Temperatur " + str(self.temp_gpu) + " °C")
        writeLog("__SYSTEM - CPU Temperatur " + str(self.temp_cpu) + " °C")
        writeLog("__SYSTEM - GPU Temperatur " + str(self.temp_gpu) + " °C")
 


class Client(asyncore.dispatcher_with_send):
    def __init__(self, socket=None, pollster=None):
        asyncore.dispatcher_with_send.__init__(self, socket)
        self.data = ''
        if pollster:
            self.pollster = pollster
            pollster.register(self, select.EPOLLIN)

    def handle_close(self):
        if self.pollster:
            self.pollster.unregister(self)

    def handle_read(self):
        receivedData = self.recv(8192)
        if not receivedData:
            self.close()
            return
        receivedData = self.data + receivedData
        while '\n' in receivedData:
            line, receivedData = receivedData.split('\n',1)
            self.handle_command(line)
        self.data = receivedData

    def handle_command(self, line):
        if line == 'get cpu':
            ausgabe=(str(Raspi_Temperatures.temp_cpu)+" °C\n")
            self.send(ausgabe)
        elif line == 'get gpu':
            ausgabe=(str(Raspi_Temperatures.temp_gpu)+" °C\n")
            self.send(ausgabe)
        else:
            self.send('unknown command')

class Server(asyncore.dispatcher):
    def __init__(self, listen_to, pollster):
        asyncore.dispatcher.__init__(self)
        self.pollster = pollster
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.bind(listen_to)
        self.listen(5)

    def handle_accept(self):
        newSocket, address = self.accept()
        print(str(get_systemzeit()) + " : Connected from" + str(address))
        writeLog("Connected from" + str(address))
        Client(newSocket,self.pollster)

class EPoll(object):
    def __init__(self):
        self.epoll = select.epoll()
        self.fdmap = {}

    def register(self, obj, flags):
        fd = obj.fileno()
        self.epoll.register(fd, flags)
        self.fdmap[fd] = obj

    def unregister(self, obj):
        fd = obj.fileno()
        del self.fdmap[fd]
        self.epoll.unregister(fd)

    def poll(self):
        evt = self.epoll.poll()
        for fd, flags in evt:
            yield self.fdmap[fd], flags

def readwrite(obj, flags):
    try:
        if flags & select.EPOLLIN:
            obj.handle_read_event()
        if flags & select.EPOLLOUT:
            obj.handle_write_event()
        if flags & select.EPOLLPRI:
            obj.handle_expt_event()
        if flags & (select.EPOLLHUP | select.EPOLLERR | select.POLLNVAL):
            obj.handle_close()
    except socket.error, e:
        if e.args[0] not in asyncore._DISCONNECTED:
            obj.handle_error()
        else:
            obj.handle_close()
    except asyncore._reraised_exceptions:
        raise
    except:
        obj.handle_error()

def get_systemzeit():
    now = datetime.datetime.utcnow()+timedelta(hours=1)
    return(now.strftime("%d.%m.%Y %H:%M:%S"))

def writeLog(textzeile):
    logfile=open(logPath, "a")
    logfile.write(str(get_systemzeit()) + " : " + str(textzeile) + "\n")
    logfile.close()

def periodic():
    Raspi_temperatures.read()

if __name__ == "__main__":
    
    # CPU und GPU Temperaturen
    Raspi_temperatures = cls_Raspi_Temp()
    
    # Repeating Event
    schedule.every(30).seconds.do(periodic)
    
    # Event Handling starten
    pollster = EPoll()
    pollster.register(Server(("",serverPort),pollster), select.EPOLLIN)
    
    while True:
        schedule.run_pending()
        evt = pollster.poll()
        for obj, flags in evt:
            readwrite(obj, flags)

  
Und zwar geht es um die Klassen-Funktion Raspi_temperatures.read() .... ich bekomme das einfach nicht hin.
Das Script läuft ohne Fehler, ruft die entsprechende Funktion aber leider nicht auf.

Ich habe es auch mit

Code: Alles auswählen

import sched, time
und dann mit

Code: Alles auswählen

...

class cls_Raspi_Temp:
    temp_cpu = 0
    temp_gpu = 0
    
    def __init__(self):
        self.read()
        
    def read(self):
        tempFile = open( "/sys/class/thermal/thermal_zone0/temp" )
        cpu_temp = tempFile.read()
        tempFile.close()
        self.temp_cpu = float(cpu_temp)/1000
        gpu_temp = commands.getoutput( '/opt/vc/bin/vcgencmd measure_temp' ).replace( 'temp=', '' ).replace( '\'C', '' )
        self.temp_gpu = float(gpu_temp)
        print(str(get_systemzeit()) + " : CPU Temperatur " + str(self.temp_cpu) + " °C")
        print(str(get_systemzeit()) + " : GPU Temperatur " + str(self.temp_gpu) + " °C")
        writeLog("__SYSTEM - CPU Temperatur " + str(self.temp_cpu) + " °C")
        writeLog("__SYSTEM - GPU Temperatur " + str(self.temp_gpu) + " °C")
        s.enter(30, 1, Raspi_temperatures.read, ())

...

    s = sched.scheduler(time.time, time.sleep)
    Raspi_temperatures = cls_Raspi_Temp()
versucht.

Auch das klappt nicht.


Weiß bitte jemand Rat?
Wie kann ich eine Klassenfunktion alle x Sekunden ausführen während gleichzeitig der Socket-Server voll funktionsfähig bleibt?
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Timer?

Und nochwas: String Formating und zweifaches Replace.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
der_Angler
User
Beiträge: 25
Registriert: Montag 28. Januar 2013, 00:48

Sehe ich das falsch oder führt Timer die entsprechende Funktion nur einmal nach x Sekunden aus?
Ich brauche aber etwas was alle x Sekunden immer wieder ausgeführt wird.

Oder stehe ich wieder schwer auf dem Schlauch?
DaftWullie
User
Beiträge: 37
Registriert: Donnerstag 17. Mai 2012, 21:28

Die Funktion, die von Timer einmalig aufgerufen wird, könnte ja wiederum einen neuen Aufruf des Timers bewirken, usw...
BlackJack

Andererseits könnte man auch einfach einen Thread starten der eine Schleife ausführt in der nach der Aktion x Sekunden/Minuten geschlafen wird.
Benutzeravatar
Balmung
User
Beiträge: 44
Registriert: Sonntag 17. März 2013, 18:36

Oder wenn man auf Threads verzichten will:

Du könntest dem pollster.poll() ein timeout übergeben, den du berechnet hast. Du hast irgendwo einen timestamp abgelegt, wann der nächste aufruf der .read() Methode geschehen soll und wenn die aktuelle Zeit diesen Timestamp überschreitet, führst du die Funktion aus (und setzt den timestamp neu). Und die pollster.poll() bekommt ein genau passendes timeout, so dass der eben erklärte Test rechtzeitig ausgeführt wird.

Edit: wahrscheinlich macht schedule.run_pending() sogar einiges davon.. ich hab schedule + epoll + asyncore + duct-tape ehrlich gesagt nie genutzt. Mir wurde von anfang an gleich twisted empfohlen.
»Honk Honk«
der_Angler
User
Beiträge: 25
Registriert: Montag 28. Januar 2013, 00:48

so, also einiges was hier kam war mir dann doch zu hoch, trotzdem danke.

Ich habe es jetzt mit timer() wie folgt gelöst:

Code: Alles auswählen

class cls_Raspi_Temp:
    temp_cpu = 0
    temp_gpu = 0
    
    def __init__(self):
        self.read()
        
    def read(self):
        tempFile = open( "/sys/class/thermal/thermal_zone0/temp" )
        cpu_temp = tempFile.read()
        tempFile.close()
        self.temp_cpu = float(cpu_temp)/1000
        gpu_temp = commands.getoutput( '/opt/vc/bin/vcgencmd measure_temp' ).replace( 'temp=', '' ).replace( '\'C', '' )
        self.temp_gpu = float(gpu_temp)
        print(str(get_systemzeit()) + " : CPU Temperatur " + str(self.temp_cpu) + " °C")
        print(str(get_systemzeit()) + " : GPU Temperatur " + str(self.temp_gpu) + " °C")
        writeLog("__SYSTEM - CPU Temperatur " + str(self.temp_cpu) + " °C")
        writeLog("__SYSTEM - GPU Temperatur " + str(self.temp_gpu) + " °C")
        tmpTimer = threading.Timer(30.0, self.read)
        tmpTimer.start()
Das klappt anscheinend auch ohne Probleme.
Die Funktion wird beim Initialisieren der Klasse einmal aufgerufen und dann wieder alle 30 Sekunden.
Also genau das was ich wollte.

Dafür vielen vielen Dank :)

Nur eine Frage habe ich noch, was ist mit der Antwort gemeint?
Und nochwas: String Formating und zweifaches Replace.
Habe ich irgendwo noch einen anderen Fehler?
DaftWullie
User
Beiträge: 37
Registriert: Donnerstag 17. Mai 2012, 21:28

der_Angler hat geschrieben:Nur eine Frage habe ich noch, was ist mit der Antwort gemeint?
Und nochwas: String Formating und zweifaches Replace.
Habe ich irgendwo noch einen anderen Fehler?
Das Zusammensetzen von Strings läßt sich sehr viel eleganter und lesbarer lösen. Deine Zeile 15 z.B. (ungetestet):

Code: Alles auswählen

print ("%s : CPU Temperatur %d °C" % (str(get_systemzeit()), self.temp_cpu))

String formatting halt.
BlackJack

@der_Angler: Warum steckt die Funktion in einer Klasse? Warum hat die so einen furchtbaren Namen? Was sollen die Klassenattribute? Warum Klammern bei der ``print``-Anweisung? Warum das `commands`-Modul was deprecated ist, statt des `subprocess`-Moduls? Warum `str()` und ``+`` um Zeichenketten und Werte zusammenzusetzen statt der `format()`-Methode? Warum das alles zweimal fast identisch? Warum kein Einsatz vom `logging`-Modul? Warum mal `gpu_temp` und mal `temp_gpu`?

Fragen über Fragen… :-)
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Vermutlich der gleiche Grund warum man kein with open as verwendet oder diese IFs verwendet die vermutlich nicht gleichzeitig eintreten können oder einfach mal alle auftretene Exception abfängt.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
der_Angler
User
Beiträge: 25
Registriert: Montag 28. Januar 2013, 00:48

<- absoluter Neuling

Deshalb habe ich vieles aus Code-Schnipseln die ich im Internet gefunden und dann zusammen gesetzt habe.

Werde mir jetzt aber mal eure Stichwörter zu Herzen nehmen und schauen was ich da eventuell ändern kann ohne das es meinen Horizont komplett übersteigt.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

der_Angler hat geschrieben:Deshalb habe ich vieles aus Code-Schnipseln die ich im Internet gefunden und dann zusammen gesetzt habe.
Programmieren funktioniert so nicht. Das solltest du dir abgewöhnen, damit stößt du sehr schnell an Grenzen. Wahrscheinlich bist du dort schon angelangt. Investiere lieber die Zeit in eine intensive Durcharbeitung eines Tutorials, hier im Forum gibt es genug Vorschläge, und gehe die Probleme strukturiert an. Letztendlich ist das die viel effektivere Methode, welche auch deutlich mehr Spaß macht. Ganz generell gilt: Wenn du Code nicht verstehst, dann verwende ihn nicht. Lies dir dazu die Dokumentation durch, spiele ggf. ein wenig damit und teste das Erlernte in Beispielen. Dann wirst du sehr schnell ein Gefühl für den Quelltext entwickeln und deutlich weniger Frust wegen ständigen Fehlern schieben.
Das Leben ist wie ein Tennisball.
der_Angler
User
Beiträge: 25
Registriert: Montag 28. Januar 2013, 00:48

Leider habe ich nicht soviel Zeit mich mit Python zu beschäftigen, deswegen hat es etwas länger gedauert bis ich mein Script entsprechend geändert bekommen habe.
Jetzt bin ich also hoffentlich einen Schritt weiter und möchte im Detail auf eure Antworten eingehen.
Programmieren funktioniert so nicht. Das solltest du dir abgewöhnen, damit stößt du sehr schnell an Grenzen. Wahrscheinlich bist du dort schon angelangt. ...
Mir ist klar das Programmieren so nicht funktioniert, ich programmieren jetzt schon über 20 Jahre hin und wieder.
Über Python habe ich mir deshalb auch ein Buch gekauft und diverse Tutorials angeschaut, nur klappt das so bei mir nicht.
Ich kann nicht anhand von nutzlosen Beispielen programmieren lernen, ich brauche einen konkreten Anwendungsfall der für mich von Interesse ist.
Dann arbeite ich den Code Schritt für Schritt durch und versuche auf diese Weise zu verstehen wie die Sprache funktioniert.
Natürlich nutze ich dabei nebenher auch Handbücher und Tutorials um ein besseres Verständnis zu bekommen.
Letztendlich denke ich nicht das man den Code immer komplett verstehen muss, man muss nur wissen wie man ihn anwendet. Aber ja, besser ist es natürlich ihn auch zu verstehen.
Bei Python kommen noch 1-2 zusätzliche Dinge dazu die mir Probleme bereiten. Zum einen das es quasi 2 x Versionen gibt (2.7 und 3.x) und diese nicht immer identisch sind und zum anderen das ich auf einem Windows System für Linux Systeme entwickle, d.h. ich bekomme Fehler in PyDev angezeigt die unter Linux keine Fehler sind.
Trotzdem habe ich mich die letzten Tage intensiver mit Tutorials beschäftigt und versucht das ganze strukturierter anzugehen - wie du mir auch geraten hast.
Warum steckt die Funktion in einer Klasse?
Okay, eigentlich ist ne Klasse eine Art Schablone und in meinem Fall gibt es die Klasse nur ein einziges mal (es gibt nicht mehrere RasPi's, sondern nur exakt einen). Von daher ist mir auch klar das ich anstatt einer Klasse auch eine normale Funktion + 2 x globale Variablen hätte nutzen können.
Soweit ich OOP und Klassen verstanden habe, dienen diese aber auch dazu Daten+Funktionen zu kapseln. Und genau das hatte ich hier vor, ich kapsel die Variablen und die Funktion zum auslesen derselben in einer Klasse. Als Nebeneffekt finde ich das Script so übersichtlicher und reduziere die Zugriffszeiten (dürfte schneller gehen über den Socket Server die Variablen auszulesen, als diese jedesmal extra aus dem RasPi auszulesen).
Ist das jetzt so falsch?
Warum hat die so einen furchtbaren Namen?
Das ist ja wohl Ansichtssache, und was ist daran eigentlich so schlimm?
Was sollen die Klassenattribute?
Ist das nicht offensichtlich? Darin stehen die entsprechenden Werte? Was ist daran schlimm?
Ich frage über eine APP (NetIO) die Temperaturen regelmäßig alle x-Sekunden ab, und dafür nutze ich diese Variablen.
Warum Klammern bei der ``print``-Anweisung?
Mein Fehler, das kam wegen den Wechsle zwischen 2.7 <-> 3.2.
Habe ich geändert.
Warum das `commands`-Modul was deprecated ist, statt des `subprocess`-Moduls?
Weil das so in einem aktuellen Blogeintrag zum Thema RasPi stand.
Habe mich aber eingelesen und das Ganze geändert.
Warum `str()` und ``+`` um Zeichenketten und Werte zusammenzusetzen statt der `format()`-Methode?
Ebenfalls mein Fehler, so stand es in meinem Buch und auch in mehreren Tutorials.
Ich wusste es auch nicht besser - habe mich eingelesen und das Ganze auch geändert.
Warum das alles zweimal fast identisch? Warum kein Einsatz vom `logging`-Modul?
Hätte nicht erwartet das das logging-Modul so einfach zu benutzen ist, bin positiv überrascht und habe beides geändert.
Doppelte Ausgabe ist entfernt und logging-Modul wird benutzt.
Warum mal `gpu_temp` und mal `temp_gpu`?
Quick & Dirty programmiert und nicht darauf geachtet.
Habe ich natürlich auch geändert.
Vermutlich der gleiche Grund warum man kein with open as verwendet
Wieder einmal habe ich den Code aus einem aktuellen Blogeintrag zum Thema RasPi und diesem einfach geglaubt.
Habe mich mit dem Thema beschäftigt und das entsprechend abgeändert.
oder diese IFs verwendet die vermutlich nicht gleichzeitig eintreten können
Das verstehe ich nicht.
Was ist an den IF's auszusetzen? Es kann ja immer nur eins der Ereignisse eintreten, also nur eine Abfrage gleichzeitig.
Bitte, wo genau ist das Problem?
oder einfach mal alle auftretene Exception abfängt.
Hier versuche ich mich einzulesen, komme aber noch nicht wirklich weiter.
Ich bin mir nicht sicher wie und wo ich die Fehler am besten abfange. Ob ich die Fehler in der Klasse abfange oder im Hauptprogramm, etc...

So, und hier jetzt erst einmal mein geändertes Script.
Ich hoffe meine Anpassungen sind so richtig.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

logPath = "/var/log/OLD_raspi_server.log"
serverPort = 54321

import asyncore
import socket
import select
import subprocess
import threading
import logging

class cls_Raspi_Temperatures:
    temperature_cpu = 0
    temperature_gpu = 0
    
    def __init__(self):
        self.__read()
        
    def __read(self):
        try: 
            with open('/sys/class/thermal/thermal_zone0/temp', 'r') as tmpFile:
                self.temperature_cpu = float(tmpFile.read())/1000
            tmpFile.closed
            self.temperature_gpu = float(subprocess.check_output(["/opt/vc/bin/vcgencmd", "measure_temp"]).replace( 'temp=', '' ).replace( '\'C', '' ).rstrip())
        except IOError as (errno, strerror):
            logger.warning('Raspberry Pi - !!! - I/O Fehler(%n): %s',errno, strerror)
        except: 
            logger.warning('Raspberry Pi - !!! - Unerwarteter Fehler')

        logger.info('Raspberry Pi - CPU Temperatur %s °C', self.temperature_cpu)
        logger.info('Raspberry Pi - GPU Temperatur %s °C', self.temperature_gpu)

        tmpTimer = threading.Timer(30.0, self.__read)
        tmpTimer.start()

class Client(asyncore.dispatcher_with_send):
    def __init__(self, socket=None, pollster=None):
        asyncore.dispatcher_with_send.__init__(self, socket)
        self.data = ''
        if pollster:
            self.pollster = pollster
            pollster.register(self, select.EPOLLIN)

    def handle_close(self):
        if self.pollster:
            self.pollster.unregister(self)

    def handle_read(self):
        receivedData = self.recv(8192)
        if not receivedData:
            self.close()
            return
        receivedData = self.data + receivedData
        while '\n' in receivedData:
            line, receivedData = receivedData.split('\n',1)
            self.handle_command(line)
        self.data = receivedData

    def handle_command(self, line):
        try:
            if line == 'get cpu':
                ausgabe=(str(Raspi_temperatures.temp_cpu)+" °C\n")
                self.send(ausgabe)
            if line == 'get gpu':
                ausgabe=(str(Raspi_temperatures.temp_gpu)+" °C\n")
                self.send(ausgabe)
        except:
            self.send('Unerwarteter Fehler')
            logger.warning('Socket Server - !!! - Unerwarteter Fehler')

class Server(asyncore.dispatcher):
    def __init__(self, listen_to, pollster):
        asyncore.dispatcher.__init__(self)
        self.pollster = pollster
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.bind(listen_to)
        self.listen(5)

    def handle_accept(self):
        newSocket, address = self.accept()
        logger.info('Connected from %s', address)
        Client(newSocket,self.pollster)

class EPoll(object):
    def __init__(self):
        self.epoll = select.epoll()
        self.fdmap = {}

    def register(self, obj, flags):
        fd = obj.fileno()
        self.epoll.register(fd, flags)
        self.fdmap[fd] = obj

    def unregister(self, obj):
        fd = obj.fileno()
        del self.fdmap[fd]
        self.epoll.unregister(fd)

    def poll(self):
        evt = self.epoll.poll()
        for fd, flags in evt:
            yield self.fdmap[fd], flags

def readwrite(obj, flags):
    try:
        if flags & select.EPOLLIN:
            obj.handle_read_event()
        if flags & select.EPOLLOUT:
            obj.handle_write_event()
        if flags & select.EPOLLPRI:
            obj.handle_expt_event()
        if flags & (select.EPOLLHUP | select.EPOLLERR | select.POLLNVAL):
            obj.handle_close()
    except socket.error, e:
        if e.args[0] not in asyncore._DISCONNECTED:
            obj.handle_error()
        else:
            obj.handle_close()
    except asyncore._reraised_exceptions:
        raise
    except:
        obj.handle_error()

if __name__ == "__main__":
    
    # Logging initialisieren
    logger = logging.getLogger('raspi_server')
    logger.setLevel(logging.DEBUG)
        
    # Logging auf die Console
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s : %(message)s','%Y-%m-%d %H:%M:%S')
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)
    
    # Logging in Datei
    file_handler = logging.FileHandler(logPath, mode='w', encoding=None, delay=False)
    file_handler.setLevel(logging.WARNING)
    formatter = logging.Formatter('%(asctime)s : %(levelname)s - %(message)s','%Y-%m-%d %H:%M:%S')
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    logger.info('System startet ...')

    # CPU und GPU Temperaturen
    Raspi_temperatures = cls_Raspi_Temperatures()
    
    # Event Handling starten
    pollster = EPoll()
    pollster.register(Server(("",serverPort),pollster), select.EPOLLIN)
    
    while True:
        evt = pollster.poll()
        for obj, flags in evt:
            readwrite(obj, flags)
Jetzt würde ich zum einen gerne eure Meinung dazu hören, ist das so besser?

Eure Kritik habe ich mir zu Herzen genommen und mir auch Mühe gegeben die Dinge zu verstehen.
Dafür schon einmal vielen Dank.

Aber bei den Exception's könnte ich eure Hilfe noch einmal gebrauchen.
Ich finde hier einfach den Weg nicht ... wenn ihr mich vielleicht dabei helfen könntet?
BlackJack

Deine Erklärung mit der Klasse habe ich nicht verstanden. Das ist eine Funktion. Das Du die in eine Klasse steckst ändert daran nichts, das ist einfach nur unsinnig und macht das Programm komplexer als es sein müsste. Die Klassenattribute sind ebenfalls unsinnig weil die nicht verwendet werden. Du erstellst ein Exemplar diese ”Klasse” und hast dann zwei Attribute darauf. Was ist daran jetzt besser oder übersichtlicher als eine Funktion aufzurufen, die diese beiden Werte als Rückgabewert hat? Da wird nichts gekapselt.

Der Name mach keinen Sinn. Er hat einen unnötigen Präfix, der semantisch nicht mal stimmt, weil das nur syntaktisch eine Klasse ist. Und das es eine ”Klasse” ist sieht man normalerweise daran, dass der Name mit einem Grossbuchstaben anfängt. Die Unterstriche gehören da nicht hinein.

Was die Klassenattribute sollen ist nicht offensichtlich, denn die werden doch gar nicht verwendet. Ich rede nicht von den *Instanz*attributen sondern von den *Klassen*attributen. Oder wo greifst Du auf `cls_Raspi_Temp.temp_cpu` zu? Die sind ja auch immer 0, oder werden die irgendwo mal auf etwas anderes gesetzt? Im gezeigten Quelltext jedenfalls nicht. Hoffentlich auch nicht wo anders, denn solche globalen Werte sind nicht sauber.

Die ``if``\s werden trotzdem ausgeführt, also die Bedingungen werden überprüft, auch wenn dem Programmierer/Leser eigentlich klar ist, dass wenn eine Bedingung zutrifft die anderen nicht zutreffen können und man sie deswegen nicht testen braucht → ``elif``.

Wenn man nicht weiss ob/wo man eine Ausnahme behandeln sollte, dann sollte man es am besten gar nicht tun. Allerhöchstens irgendwo ganz oben in der Aufrufhierarchie wenn man man das Programm zum Beispiel in einer Hauptschleife unbedingt davon abhalten möchte abzubrechen. Dann sollte man aber den Fehler irgendwie protokollieren, damit die nicht einfach so verschluckt werden und man sie auch finden kann. `logging` kennt dafür die `exception()`-Funktion/-Methode, die auch gleich den gesamten Traceback protokolliert. Denn von einer Warnung die einfach nur 'Unerwarteter Fehler' hat man nicht wirklich etwas wenn man den Fehler suchen und beseitigen möchte.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Stringformatierung benutzt immer noch nicht und warum benutzt du with und closed, was soll das überhaupt sein?
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
der_Angler
User
Beiträge: 25
Registriert: Montag 28. Januar 2013, 00:48

Was ein Ton hier :(
Das soll jetzt wirklich nicht falsch rüber kommen, aber anscheinend habe ich hier die absoluten Python-Götter vor mir.
Irgendwie ist alles, aber wirklich alles was ich woanders im Netz finde eurer Meinung nach Quatsch und falsch. :(
Ich finde das sehr schade, so vertreibt man Anfänger.
Oder wo greifst Du auf `cls_Raspi_Temp.temp_cpu` zu?
Entweder reden wir komplett aneinander vorbei oder du hast den Code nicht gelesen?
Hier greife ich darauf zu:

Code: Alles auswählen

            if line == 'get cpu':
                ausgabe=(str(Raspi_temperatures.temp_cpu)+" °C\n")
                self.send(ausgabe)
Die sind ja auch immer 0
Sicher nicht, mit

Code: Alles auswählen

            with open('/sys/class/thermal/thermal_zone0/temp', 'r') as tmpFile:
                self.temperature_cpu = float(tmpFile.read())/1000
            tmpFile.closed
            self.temperature_gpu = float(subprocess.check_output(["/opt/vc/bin/vcgencmd", "measure_temp"]).replace( 'temp=', '' ).replace( '\'C', '' ).rstrip())
werden beide Variablen gesetzt.
Die ``if``\s werden trotzdem ausgeführt, also die Bedingungen werden überprüft, auch wenn dem Programmierer/Leser eigentlich klar ist, dass wenn eine Bedingung zutrifft die anderen nicht zutreffen können und man sie deswegen nicht testen braucht → ``elif``.
Was dann jetzt? In meinem ersten Code-Beispiel, ganz oben (an den Anfang scrollen) hatte ich noch "elif" genutzt und dort wurde dann auch gemeckert ... wie ich es mache, es ist falsch.
Was ist daran jetzt besser oder übersichtlicher als eine Funktion aufzurufen, die diese beiden Werte als Rückgabewert hat?
Das ich dann jedes mal einen Diskzugriff hätte, der sicher länger dauert als nur schnell die Variabel auszulesen.
Und auf einem Raspberry Pi versuche ich Zeit zu sparen wo es geht.
Allerhöchstens irgendwo ganz oben in der Aufrufhierarchie wenn man man das Programm zum Beispiel in einer Hauptschleife unbedingt davon abhalten möchte abzubrechen. Dann sollte man aber den Fehler irgendwie protokollieren, damit die nicht einfach so verschluckt werden und man sie auch finden kann. `logging` kennt dafür die `exception()`-Funktion/-Methode, die auch gleich den gesamten Traceback protokolliert. Denn von einer Warnung die einfach nur 'Unerwarteter Fehler' hat man nicht wirklich etwas wenn man den Fehler suchen und beseitigen möchte.
Danke, das hilft mir wirklich weiter.
Damit werde ich mich gleich befassen :D
Stringformatierung benutzt immer noch nicht
Wo gebe ich den Strings noch mit "+str()" aus?
Was ist den an dieser Lösung falsch, bzw. nicht formatiert?

Code: Alles auswählen

logger.info('Raspberry Pi - GPU Temperatur %s °C', self.temperature_gpu)
warum benutzt du with und closed, was soll das überhaupt sein?
Hier könnte ich wieder heulen. Erst wird gemeckert das ich mit "open as" arbeiten soll.
Vermutlich der gleiche Grund warum man kein with open as verwendet
Dann suche ich im Internet nach einem entsprechend Tutorial und baue es ein - wieder falsch. :?


Sry Leute, da steige ich nicht mehr durch, mal so, mal so, rüder Ton (m.M.) und nur wenig wirkliche Hilfe.

Schade, echt schade, den ich hatte wirklich gehofft hier geholfen zu bekommen. :cry:
Und nein, ich wollte kein fertiges Skript geliefert bekommen sondern nur 2-3 Zeilen Code als Hinweis wie es besser/richtig ist.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

der_Angler hat geschrieben:Was ein Ton hier :(
Das soll jetzt wirklich nicht falsch rüber kommen, aber anscheinend habe ich hier die absoluten Python-Götter vor mir.
Ja, da hast du recht, da ist der Ton tatsächlich etwas härter ausgefallen als nötig ist.
der_Angler hat geschrieben:Irgendwie ist alles, aber wirklich alles was ich woanders im Netz finde eurer Meinung nach Quatsch und falsch. :(
Es ist tatsächlich so dass im Rasberry Pi-Umfeld unglaublich schlechter Code zu sehen ist. Das macht mir fast schon Angst, weil die Leute dann kompletten Stuss zusammenschreiben (weil es geht ja) und dass es dann furchtbar zum warten oder nachvollziehen ist, ist dann egal. Noch stolz nen Blogpost oder ein Tutorial mit dem schlechten Code schreiben und passt :|
der_Angler hat geschrieben:
Oder wo greifst Du auf `cls_Raspi_Temp.temp_cpu` zu?
Entweder reden wir komplett aneinander vorbei oder du hast den Code nicht gelesen?
Ich glaube ersteres: Klassenattribute und Instanzattribute sind unterschiedliche Sachen. Das was du in Zeile 15 und 16 definierst sind Klassenattribute. Das was du in Zeile 24 setzt sind Instanzattribute.
der_Angler hat geschrieben:
Stringformatierung benutzt immer noch nicht
Wo gebe ich den Strings noch mit "+str()" aus?
Zeile 64, Zeile 67 sind mir jetzt beim durchschauen aufgefallen. Du solltest deinen eigenen Code tatsächlich etwas sorgfältiger lesen.
der_Angler hat geschrieben:
warum benutzt du with und closed, was soll das überhaupt sein?
Hier könnte ich wieder heulen. Erst wird gemeckert das ich mit "open as" arbeiten soll.
Man soll natürlich das ``with``-Statement nutzen, aber dann ist die Zeile 25 komplett überflüssig. Und auch sonst sinnlos, weil das ist ja nur der Name eines Objektes, damit wird nichts gemacht, also ist diese Zeile so wie sie da steht unsinnig.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

@der_Angler: Bei einer Funktion hätte man genau die gleichen Diskzugriffe wie bei der Klasse. Man müsste sich nur die Ergebnisse an passenderer Stelle merken.

Ergänzend zu Leonidas: Du machst da ja fröhlich mit indem Du Sachen irgendwo abschreibst die Du nicht vollständig verstehst, und damit weder beurteilen kannst ob das tatsächlich funktioniert, noch wie sinnvoll der Code insgesamt ist. Was hier passiert ist das selbe weshalb so viel verdammt schlechter PHP-Quelltext da draussen zu finden ist — Leute die keine Ahnung haben schreiben von Leuten die keine Ahnung haben ab, immer nach der Devise „Hauptsache es funktioniert”, zumindest oberflächlich betrachtet.

Gibt es zum Beispiel eine Begründung für die verhältnismässig aufwändige und low-level `asyncore`/`epoll`-Lösung, ausser dass Du die irgendwo so fertig gefunden hast?

Edit: Im `Client` fiel mir gerade ein Fehler auf: Wenn beim `pollster`-Argument nichts übergeben wurde, dann wird auch das gleichnamige Attribut nicht gesetzt. Das wird dann in den Methoden die versuchen drauf zuzugreifen zu einem Fehler führen.
Antworten