Ein Feld aus einer Funktion übernehmen

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.
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

Hallo,
ich habe eine Datei, welche ich jeden Tag neu einlesen muss. Ich dachte mir, ich könne das über eine Funktion erledigen, bekomme es aber nicht hin. Leider finde ich geade zu meinem Problem nichts in Büchern oder dem Netz.
Vielleich kann ich es auch nur nicht lesen. Folgender Code:

Code: Alles auswählen


# Daten neu einlesen 

def DatenHolen():
  Eingabe=open("/mnt/netz/Python/Transponder.txt", "r")
  for Zeile in Eingabe:
    if (len(Zeile)>2):
      Werte=Zeile.split(";")
      fld.append(Werte)
  Eingabe.close()
  return fld

#*************************Hauptprogramm
fld=[]
DatenHolen
for zeile in fld:
  print zeile[1]
Das Feld fld wird zwar korrekt gefüllt, jedoch weiß ich nicht, wie ich darauf zugreifen kann.
Ich dachte, wenn ich zuerst die Variable fld definiere und im 2. Schritt die Funktion aufrufe, habe ich die Werte in der Liste. Leider funktioniert das nicht so.
Wenn sich jemand finden würde, der es mir verständlich erklären könnte, wäre ich dankbar. Ich bitte um Nachsicht, das sind meine 1. Python-Stunden.

PS: Wenn ich das Einlesen aus der Funktion nehme, funktioniert alles korrekt.

Gruß Lothar
BlackJack

@LotharK: Die `open()`-Funktion öffnet eine Datei und gibt ein Datei-Objekt zurück. Schau Dir doch mal an wie man an das Objekt kommt. Gleiches gilt für die `len()`-Funktion die eine Zahl zurück gibt und die `split()`-Methode die eine Liste zurück gibt.

Und Du musst Deine Funktion auch *aufrufen*, nicht einfach nur ihren Namen hinschreiben.

Das Hauptprogramm sollte auch in einer Funktion stehen, denn dann würde auffallen das die `DatenHolen()`-Funktion versucht `fld` zu verändern was *ausserhalb* der Funktion definiert wurde, was man tunlichst vermeiden sollte. Funktionen sollten so geschrieben werden das Werte die Funktion als Argumente betreten und als Rückgabewerte verlassen. Wenn Funktionen einfach so Variablen „aus der Umgebung” benutzen und verändern wird ein Programm sehr schnell unübersichtlich bis unwartbar.

Beim ``if`` sind unnötige Klammern um die Bedingung gesetzt.

Dateien öffnet man am besten zusammen mit der ``with``-Anweisung, dann kann man sich das `close()` sparen und die Datei wird auf jeden Fall geschlossen wenn der ``with``-Block verlassen wird.

Bezüglich der Namensschreibweise empfiehlt sich ein Blick in den Style Guide for Python Code.

Und welches Tutorial erklärt Funktionen so schlecht? Beziehungsweise hast Du das in der Python-Dokumentation mal durchgearbeitet?
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

Hi,

Danke erst mal für die Antwort. Wie gesagt, das sind meine 1. Python-Tage. Ich wende immer die Denkweise anderer Programmierumgebungen an. Was Du schreibst, ist ne Menge Stoff für einen Anfänger.
Ich dachte mir, wenn ich fld außerhalb der Funktion definiere, wäre sie vielleicht "GLOBAL". Das das nicht so ist, habe ich ja gemerkt.

Das ganze, wie ich Dateien öffne und das mit den Klammern habe ich aus einem Fachbuch. Natürlich habe ich die Python-Dokumentation noch nicht durchgearbeitet. Da bich ich ja soeben erst am Anfang.
Da ich die Forenbeiträge und Tutorials nicht umsetzen konnte, habe ich halt hier mal gefragt wie's geht. Wie ich jetzt das fld aus der Funktion bekomme, habe ich immer noch nicht begriffen. Zuerst hatte ich es mit: fld=DatenHolen versucht, das terminiert mir aber mit Fehler. Vom Verständnis her, hätte ich fld[]=DatenHolen genommen, was aber auch nicht funzt.

OK, ich werde jetzt mal versuchen, Deine Tipps umzusetzen. :(

Ciao Lothar
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@LotharK: Wie man Funktionen aufruft und wie man Parameter übergibt und Rückgabewerte bekommt, ist in vielen Programmiersprachen gleich. Auch dass man globale Variablen tunlichst vermeiden soll, ist in jeder Programmiersprache, die das Konzept Funktion sinnvoll umsetzt, gleich.
Rumraten wird Dich nicht weit bringen. Ein Tutorial durchzuarbeiten ist essentiell. Dass "fld=DatenHolen" direkt einen Fehler meldet, bezweifle ich mal. Wenn Du Fehler bekommst, hilft es, diese mit dem Gesamten Traceback hier zu posten, weil sonst können die Lesen nur raten.
BlackJack

@LotharK: `fld` *ist* in Deinem Skript (modul)global, das sollte es aber nicht sein. Aus genannten Gründen — man handelt sich damit abhängigkeiten zwischen Funktionen ein die nicht auf den ersten Blick ersichtlich sind und den Quelltext schnell unverständlich machen, und schwer zu testen auch, denn es reicht dann nicht die normale Schnittstelle der Funktion zu kennen, sondern muss auch noch vor dem Aufruf für bestimmte Bedingungen in der Umgebung sorgen, die nicht offensichtlich sind. Also zum Beispiel in diesem Fall das eine Liste mit einem bestimmten Namen vor dem Aufruf im Modul existieren muss.

Auch wenn das Öffnen der Datei aus einem Buch abgeschrieben ist, Du siehst doch wie dort der Rückgabewert der Funktion weiterverwendet wird. Er wird an einen Namen gebunden.

``fld=DatenHolen`` ist schon fast richtig und führt selber noch nicht zu einem Fehler. Was die Zeile macht ist die *Funktion* `DatenHolen` an den Namen `fld` zu binden. Danach ist sie unter zwei Namen bekannt: `DatenHolen` und `fld`. Was dann zum Fehler führt ist der Versuch mit einer ``for``-Schleife über die Funktion zu iterieren. Was sollte das auch bedeuten? Du musst die Funktion *aufrufen* und zwar wie alle anderen Funktionen (und Methoden) die Du in dem Quelltext schon aufrufst durch die runden Klammern die rechts von der Funktion stehen müssen. Das muss man auch machen wenn keine Argumente übergeben werden, dann bleiben die Klammern halt leer. Wie zum Beispiel beim `close()`-Aufruf in dem Quelltext. Da Funktionen in Python auch Werte sind, muss man ja irgendwie den Wert von einem Aufruf unterscheiden können.

Edit: Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function

TRANSPONDER_FILENAME = '/mnt/netz/Python/Transponder.txt'


def load_transponders(filename):
    with open(filename, 'r') as lines:
        return [line.split(';') for line in lines if len(line) > 2]


def main():
    transponders = load_transponders(TRANSPONDER_FILENAME)
    for row in transponders:
        print(row[1])


if __name__ == '__main__':
    main()
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

LotharK hat geschrieben:Zuerst hatte ich es mit: fld=DatenHolen versucht, das terminiert mir aber mit Fehler. Vom Verständnis her, hätte ich fld[]=DatenHolen genommen, was aber auch nicht funzt.
Auch wenn die grundlegenden Konzepte sich zwischen den verschiedenen Programmiersprachen oft ähneln, so ist die Syntax keinesfalls immer gleich. Python hat keinen fest in die Sprache verankerten Array-Datentypen. Man nutzt dafür stattdessen Listen. Und an die wird, wie bei allen anderen Objekten auch, einfach ein Name gebunden, sofern man sie im Namensraum ablegen möchte. In deinem Fall wäre das also:

Code: Alles auswählen

fld = DatenHolen()
EDIT: Wobei ich hier davon ausgehe, dass die aufgerufene Funktion sich selbständig um die Erzeugung und Rückgabe der Liste kümmert.
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

Hallo,

erst mal danke für die antworten.

@Sirius - Deine Aussage mit den globalen Variablen ist schlicht falsch. Nehmen wir z.B. VB. Am besten VB6. Wenn ich Formularübergreifend und modular programmieren will, MUSS ich globale Variablen verwenden. Das ist zwingend und keines falls falsch.
fld=DatenHolen bringt keinen Fehler, aber fld[]=Datenholen schon. Rumraten - OK, das bringt mich nicht weiter, aber sei mal ehrlich - wenn bei Dir etwas nicht funktioniert, versuchst du es erst mal auf andere Art, oder arbeitest Du sofort sämtliche verfügbaren Tutorials durch? (sorry)

Klar habt ihr mir jetzt schön erklärt, wie es nicht geht und das ich was falsch gemacht habe. Simple Ergebnisse einer Funktion aus der Funktion zu bekommen habe ich begriffen, wie ich aber ein Feld zurück gebe, weiß ich immer noch nicht. Ist return fld falsch?
Die Werte rechts in der Klammer, falls es welche gibt, sind doch Werte, die in der Funktion verarbeitet werden, oder? Ich denke, wenn ich return fld schreibe, gebe ich dann nicht das gesamte Feld zurück?

Vielleich hat ja jemand ein kurzes Beispiel, um bei mir den Groschen fallen zu lassen.
Ich wende mich ja deshalb ans Forum, weil ich es selbst nicht weiß.

@snafu so hatte ich es anfangs gemacht - da kam aber in Zeile 16 ein Fehler (Function object is not literable)

Ciao Lothar
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

@BlackJack

Danke für die Ausführung und den Sourcecode.
Dieser unterscheidet sich mächtig von dem, was bei mir in meinen 2 (neu gekauften') Büchern steht. :cry: Ich werde mir das jetzt mal gründlich durch den Kopf gehen lassen.
Sieht erst mal etwas undurchsichtig für mich aus. (Bis jetzt benötigte ich für ein With immer ein End With)

Ich tippe den Code jetzt mal ab und versuche es zu verstehen.

DANKE!!

Gruß Lothar
BlackJack

@LotharK: Ich arbeite nicht sämtliche Tutorials durch aber mindestens das in der Dokumentation vorhandene oder empfohlene Grundlagentutorial. Und zwar *bevor* ich irgendetwas mit der Sprache programmiere. Woher soll man denn sonst wissen wie die Sprache funktioniert und wie will man etwas programmieren ohne zu wissen wie die Sprache funktioniert? Ich habe schon genug Sprachen angeschaut um zu wissen das eine neue Sprache lernen nicht nur heisst zu schauen welche Art von Klammern Blöcke kennzeichnen, sondern das Sprachen sehr unterschiedlich funktionieren. Selbst welche bei denen die Syntax sehr ähnlich ist. Darum bringt es nichts sich nur irgendwelche Beispiele anzuschauen und zu raten was die bedeuten mögen.

Die Ausage von Sirius3 ist nicht falsch, er hat das ja auf Sprachen eingeschränkt die das Prinzip Funktion *sinnvoll* umsetzen. Beziehungsweise kann man das auch auf Objektorientierung erweitern. Wenn einen VB6 also zu globalen Variablen zwingt, ist das dort von der Sprache her einfach schlecht umgesetzt. Wie auch immer: In Python bitte keine globalen Variablen.

Es gibt keine simplen und anderen Ergebnisse. ``return`` ist für alles gleich. Danach muss ein Ausdruck stehen der zu einem Wert ausgewertet wird, und dieser Wert wird an den Aufrufer übergeben. Dabei spielt es keine Rolle ob der Wert eine Zahl, eine Zeichenkette, eine Liste, ein Tupel, oder irgendein anderer Datentyp ist. Du gibst da zwar die den Wert der an den Namen `fld` gebunden ist zurück, aber das ist im Grunde sinnfrei weil der ja gar nicht in der Funktion erzeugt wird, sondern ein Name ist der auf Modulebene existiert, an der der Aufrufer in diesm Fall also auch so heran kommen würde. Was aber wie gesagt nicht so sein sollte. Die Liste sollte *in* der Funktion erstellt werden, damit jeder Aufruf unabhängig von anderen Code in dem Modul ist.

Endkennzeichnungen für Blöcke im Quelltext braucht man in Python ja grundsätzlich nicht weil das durch die Einrückung geregelt ist. Und ``with`` ist auch so ein Fall bei dem man in der Dokumentation nachlesen muss und nicht durch raten weiterkommt (oder nur durch Zufall) weil verschiedene Programmiersprachen zwar eine ``with``-Anweisung kennen, die aber nicht überall auch nur annähernd die gleiche Bedeutung hat.

Stichwort für den Ausdruck nach dem ``return`` ist übrigens „list comprehension”.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@LotharK: Verschiebe das ``fld = []`` (Erzeugung der Liste) in deine Funktion. Die Liste sollte hierbei natürlich vor Eintritt in die ``for``-Schleife erstellt werden. Dann sollte es wie erwartet funktionieren. Du hast dann die Erstellung der Datenstruktur (hier: Liste) in der Funktion. Und die Rückgabe von ``fld`` machst du ja eh schon, was auch so bleiben soll.

Über das Ergebnis kannst du dann so iterieren:

Code: Alles auswählen

for zeile in DatenHolen():
    print zeile[1]
Es ist eigentlich gar nicht so kompliziert. Man muss es nur mal gemacht und auch verstanden haben. ;)

Und wie gesagt: ``fld = []`` hat dann außerhalb der Funktion gar nichts mehr zu suchen.

EDIT: Das Problem war halt, dass du zuvor über die Funktion an sich iterieren wolltest - daher die Fehlermeldung. Du willst aber über das Ergebnis iterieren - also Klammern hinter den Funktionsnamen setzen. Funktion sind in Python auch ganz normale Objekte. So kann man z.B. ein paar Funktionen in eine Liste stecken, sie an anderer Stelle aus der Liste holen und erst dann mit diesen Funktionen den eigentlichen Aufruf machen durch das Setzen von Klammern.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

LotharK hat geschrieben:@Sirius - Deine Aussage mit den globalen Variablen ist schlicht falsch. Nehmen wir z.B. VB. Am besten VB6. Wenn ich Formularübergreifend und modular programmieren will, MUSS ich globale Variablen verwenden. Das ist zwingend und keines falls falsch.
Ich programmiere seit Jahren gezwungenermaßen im Job noch VBA (VB6). Wenn ich dort passende Klassenstrukturen verwende, dann muss ich nicht mit globalen Werten operieren. Abgesehen davon ist VB6 eine grauenhafte Sprache die den Entwickler sehr leicht dazu bringt, kaputte Konzepte zu verwenden.
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

@BlackJack
Danke - Dein Code funktioniert erst mal. Leider ist es nicht das, was ich eigentlich will. Ich werde mal beschreiben, was ich mit meinem Code erreichen wollte.

(Vorab - sicher gibt es eine elegantere Lösung)

Ich habe eine Liste fld. Diese wird beim Start mit den Transpondernummern der einzelnen Mitarbeiter gefüllt. Transponder-Nr, Personal-Nummer, Name, Recht1..... bis Recht 22 für die einzelnen Türen. (Zutrittskontrolle)

Wenn jemand seinen Chip an den Leser hält, wird im Code ein Interrupt ausgelöst, die Liste durchlaufen und geschaut, ob der Chip Rechte für die Tür hat.
Wenn ja, Tür öffnen, wenn nicht, Fehlerton. Das Ganze auf Display ausgeben.
Um die Daten aktuell zu halten, wird jede ca.10 Minuten auf dem Server geprüft, ob die Personalabteilung etwas geändert hat.
Wenn ja, wird die Liste neu eingelesen. Wenn nicht, bleibt die Liste unverändert.
Das 10minütige Einlesen wollte ich über einen timer realisieren, finde aber nichts. Jetzt habe ich es erst mal mittels Interrupt über einen Pin von außen gelöst. (AtTiny15)

Deine Routine holt sich jedes Mal die Daten übers Netz. Gäbe es eine Störung, würde die Tür u. U. nicht öffnen, da keine Daten vorhanden sind.
Da es sich um 22 Raspis und mehrere 1000 DS handelt, habe ich schon ganz schönen Verkehr auf der Leitung. Zumal es zu langsam funktioniert. Die Daten liegen im AD unseres Systems (NTFS)

Das ganze Gedöns ich schon lauffähig und funktioniert einwandfrei. (Nur die Daten werden jetzt erst ein Mal bei Start geholt. Da ich das über einen INT lösen wollte, habe ich das mit einer Funktion testen wollen.
Das ist der Hintergrund.
Wenn das Datei Öffnen und Daten holen mit im main steht, funktioniert es.

Vielleicht wird mein Problem jetzt klarer.

Ich muss also in eine Liste haben, die im main läuft und Daten hat, die mittels Funktion ab und zu neu gefüllt wird.
In den anderen, mir bekannten Programmiersprachen ist das überhaupt kein Problem und sicher gibt es hier eine Lösung.


Ciao LotharK
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@LotharK: Dann wäre es sauberer, die Aufgabe über eine eigens dafür entworfene Klasse zu lösen. Von Funktionen erwartet man in Python normalerweise nicht, dass sie Modifikationen an einem übergebenen Objekt vornehmen. Die Rückgabe dieses Objektes ist dann auch unsinnig, da der aufrufende Code ja ohnehin schon die Kontrolle über das Objekt hatte.

Du musst dir also überlegen, ob du etwas zusätzliche Zeit in ein halbwegs brauchbares Klassendesign investierst, mit dem man vernünftig arbeiten kann, oder ob du weiterhin mit fehleranfälligen Idiomen hantieren möchtest.

Man könnte natürlich auch mit einer globalen Konstante arbeiten, hinter der die Liste steckt. Dann muss sich der Aufrufer zumindest nicht um die Bereitstellung der Datenstruktur kümmern. Aber eigentlich sind halt Klassen für diesen Zweck gedacht.
BlackJack

@LotharK: Das klingt nach einem Fall für das `threading`-Modul und einer Schleife die alle 10 Minuten die Daten gegebenenfalls neu einliest.

Die Datenstruktur für `fld` (und auch der Name) klingt unpassend. Man will ja eigentlich eine Abbildung von Transpondernummer auf die dazugehörigen Daten und die Rechte sind dann ja auch wieder ein zusammengesetztes Datum was nicht auf einer Ebene mit dem Rest existieren sollte. Da würde sich wahrscheinlich auch ein `set()` für die Rechte anbieten.
BlackJack

@LotharK: Ich frage mich gerade: Wenn die Chips per Interrupt, also nebenläufig abgearbeitet werden, und das regelmässige einlesen der Datei auch nebenläufig passieren soll, was macht dann das Hauptprogramm eigentlich?
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@LotharK: Weil ich mich gerade mit FRP und DDD beschäftige ;): http://www.python-forum.de/pastebin.php?mode=view&s=425

Läuft nur unter Python 3.4 auf unixoiden Betriebssystemen (wg. SIGALRM). Du willst ja sowieso auf andere Signale reagieren, also einfach die einsetzen. Man kann es auch leicht nach Python 2.7 portieren, Enums zB. gibt es als Backport. Die DB ist ein Dummy und muss durch eine richtige ersetzt werden, ebenso alles, was ich zu Demo-Zwecken mittels random simuliert habe.

Wenn man es laufen lässt, kommt ungefähr sowas als Ausgabe:

Code: Alles auswählen

Door(1) access for [Staffer(5), Staffer(1), Staffer(2)]
Door(2) access for [Staffer(2), Staffer(5), Staffer(1), Staffer(3)]
Door(3) access for [Staffer(4), Staffer(2)]
NOT opening Door(3) for Staffer(3)
opening Door(2) for Staffer(2)
NOT opening Door(1) for Staffer(3)
Door(1) access for [Staffer(1)]
Door(2) access for [Staffer(5), Staffer(1), Staffer(4)]
Door(3) access for [Staffer(3), Staffer(5)]
NOT opening Door(2) for Staffer(2)
opening Door(1) for Staffer(1)
opening Door(2) for Staffer(4)
Door(1) access for [Staffer(2), Staffer(4)]
Door(2) access for [Staffer(2)]
Door(3) access for [Staffer(1), Staffer(5), Staffer(2), Staffer(4)]
NOT opening Door(3) for Staffer(3)
opening Door(2) for Staffer(2)
NOT opening Door(1) for Staffer(3)
Door(1) access for [Staffer(3), Staffer(4)]
Door(2) access for [Staffer(1)]
Door(3) access for [Staffer(1)]
opening Door(3) for Staffer(1)
NOT opening Door(2) for Staffer(5)
NOT opening Door(3) for Staffer(2)
...
Und ein *beep* für jedes Nicht-Öffnen einer Tür.
In specifications, Murphy's Law supersedes Ohm's.
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

Hallo BlackJack,

@BlackJack
Ich habe hier in der Fa. mehrere Türen( insgesamt 22 mit Lager) welche alle mit Transponder geöffnet werden. Ist ein Transponder verloren, oder es kommt ein neuer Mitarbeiter, muss eine Fa. jedes Mal indie neuen Daten in jede Steuerung eintragen. Das ist sehr kostspielig.
Frage nicht, was ein vernetztes System kostet.

Ich ersetze diese Steuerungen durch Raspi.

Das System macht also nichts anderes, als die ganze Zeit zu lauern, ob jemand durch die Tür will. Kommt jemand, wird die Transponder-Nr eingelesen. Das System prüft, ob der betreffende TP im System ist. Wenn ja, wird geprüft, für welche Türen er Rechte hat.
Hat er, wird die Tür geöffnet. Das Ganze wird mitgelockt und steht im System zur Verfügung.
Die Vorteile liegen klar auf der Hand. Die Personalabteilung kann nun bequem Transponder und Rechte verwalten. Ebenso kann nachvollzogen werden, wann und wo jemand gekommen ist.
Das System funktioniert schon jetzt so, wie beschrieben. Nebeneffekt - ich gebe auf LCD den Benutzer aus und Zutritt erlaubt oder nicht. Das ganze mit einem Signalton und 2 Status-LEDs aufgemotzt, ist es besser als das System was jetzt gar nichts zeigt und nur durch leises Klicken signalisiert, ob die Tür offen ist.

Das Ganze wird am Notstrom hängen und zusätzlich mit 12V Bleigel gepuffert.
Wenn unser Netzwerk nicht läuft, sammelt es die Daten und gibt sie bei Erreichen wieder aus.

Soweit das Programm.
Ich hatte so ein System schon mit ATMega18 gemacht. Nur mit dem Raspi ist es einfach einfach. :)

Jetzt fülle ich das Feld Transponder_Liste (welches ich in meinem Test oben einfach fld nannte) einfach im Hauptprogramm mit einer IF-Anweisung. Wobei ein Flag geprüft wird, was ich mittels Interrupt setze.
Soweit so gut. Damit kann ich leben. Ich hätte es eben nur gern in einer Function erledigt. Wo es meiner Meinung nach auch hin gehört. Nun habe ich in dem ganzen Tread schon so viel gelesen, dass ich eigentlich alles falsch mache und dass ich keine Ahnung habe...
Ich schrieb ja auch anfangs, dass ich mich mit Python noch nicht gut auskenne.
Die Standard-Tipps, "lies erst mal ein Buch", befolgte ich auch. Nun setze ich das um und es ist auch falsch.

Leider weiß ich immer noch nicht, wie ich die Liste im Hauptprogramm prüfen, und ggf in der Function neu füllen kann.

MfG LotharK
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@LotharK: bei Deinem Problem böte sich ja ein minimalistisches Event-System an, das über eine Queue sowohl Türöffner-Interrupt als auch neue Daten an das Hauptprogramm meldet, das dann die entsprechenden Aktionen auslöst, hier mal als Template-Code:

Code: Alles auswählen

import numbers
import os
from Queue import Queue
from time import sleep

def read_rights_mapping(filename):
    pass #TODO

def get_transponder_id():
    pass #TODO

def process_door_open_request(rights, transponder):
    pass #TODO

def rights_mapping_watcher(queue):
    last_modification_time = None
    while True:
        try:
            if os.path.getmtime(RIGHTS_FILENAME) != last_modification_time:
                last_modification_time = os.path.getmtime(RIGHTS_FILENAME)
                queue.put(read_rights_mapping(RIGHTS_FILENAME))
        except Exception:
            # ignore network errors or related stuff
            logging.exception("error reading rights file")
        sleep(CHECK_INTERVAL)

def transponder_trigger(queue):
    queue.put(get_transponder_id())

def main():
    queue = Queue()
    register_trigger(transponder_trigger, args=(queue,))
    rights_watcher = threading.Thread(target=rights_mapping_watcher, args=(queue,))
    rights_watcher.deamon = True
    rights_watcher.start()
    rights = {}
    while True:
        event = queue.get()
        if isinstance(event, numbers.Integral):
            process_door_open_request(rights, event)
        else:
            rights = event

if __name__ == '__main__':
    main()
Die Funktionalität fehlt da natürlich noch, aber ich hoffe, aus den Namen wird deutlich was zu tun ist. Der Vorteil ist, dass man immer mit einer vollständigen Rechte-Tabelle arbeitet, auch wenn das Netzwerk vielleicht gerade ausgefallen ist, es gibt keine globalen Zustände und das Lesen über das Netzwerk blockiert die Tür nicht.
LotharK
User
Beiträge: 51
Registriert: Sonntag 22. März 2015, 10:02

Hallo sirius3

vielen Dank für Deine Hilfe. Natürlich habe ich den Code noch nicht vollständig verstanden. Er sieht aber vielversprechend aus. Jetzt muss ich mich erst mal an die Arbeit machen und analysieren, was die einzelnen Abschnitte tun. Z.B Import Queue und Import OS. Das finde ich aber allein raus.

Jetzt, wo ich Code habe, wird das Ganze für mich nachvollziebar.
Ich werde mich heute Abend, wenn ich Ruhe habe, damit beschäftigen.

Letztendlich ist das sowieso nur ein vorläufiges Programm. Am Ende wird das Programm auf einen MS-SQL Server 2008 R2 zugreifen. Soweit bin ich aber noch lange nicht. :?
Ich habe es jetzt aber schon mal geschafft, dass das Programm vom Netzwerk AD/Domain gestartet wird und Daten auf dem Server holt und hinterlegt.
Zwar meldet sich der Raspi an die Domäne an und hat nur Rechte auf 1 Verzeichnis und sonst nichts, trotzdem erscheint mir das Mapping mit hinterlegtem Passwort, IP und User im Klartext doch etwas unsicher. Ich habe zwar gelesen, dass man das über eine versteckte Datei handeln kann, scheint mir aber auch nicht sehr sicher. Wie das am Ende richtig geht, bekomme ich aber allein raus.

Ich möchte mich bei allen bedanken, die sich die Mühe gemacht haben, mir bei meinem Projekt weiter zu helfen.

Ciao LotharK
:lol:
PS - Nicht explodieren - Kann man nun eine Liste irgend wie als global definieren und in einer Funktion verändern? Würde mich nur mal so nebenbei noch interessieren!)
BlackJack

@LotharK: Das sind zwei Fragen. Man kann in Funktionen Listen auch verändern die als Argument übergeben werden, dazu muss die Liste nicht global sein. Nicht explodieren, aber beides sollte man eher nicht tun. :-P
Antworten