Variable in Befehl einbauen

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.
fenestro
User
Beiträge: 13
Registriert: Sonntag 20. Oktober 2013, 00:33

Guten Tag :)

Ich programmiere gerade den "Prozessor" für meine Haussteuerung mit Python, hab allerdings ein paar kleine Probleme.

Hier mein Code:

Code: Alles auswählen

	if GPIO23_in == "1":
		print "erkannt dass gpio23 input"
		if ( GPIO.input(16) == True ):
		
			print "erkannt dass schalter gedruckt"
			
			dateiname = "/var/www/settings/zuweisungen/GPIO2.txt"
			a = []
			with open(dateiname, 'r') as f:
				for line in f:
					a.append(int(line))
			
			akt1= a[1]
			akt2= a[2]
			akt3= a[3]
			
			print akt1
			print akt2
			print akt3
			
			dateiname = "/var/www/settings/onoff.txt"
			a = []
			with open(dateiname, 'r') as f:
				for line in f:
					a.append(int(line))
					
			print a[akt1]
			print a[akt2]
			print a[akt3]			
					
			if a[akt1] == a[akt2]:
				if a[akt2] == a[akt3]:
					if a[akt1] == "1":
						GPIO.output(akt1, GPIO.LOW)  //hier problem 1
						GPIO.output(akt2, GPIO.LOW)
						GPIO.output(akt3, GPIO.LOW)
						print "alle ein"
						time.sleep(2)
						
					elif a[akt1] == "0":
						GPIO.output(akt1, GPIO.HIGH)
						GPIO.output(akt2, GPIO.HIGH)
						GPIO.output(akt3, GPIO.HIGH)
						print "alle aus"
						time.sleep(2)
				
				else:
					GPIO.output(akt1, GPIO.HIGH)
					GPIO.output(akt2, GPIO.HIGH)
					GPIO.output(akt3, GPIO.HIGH)	
					print "alle aus"
					time.sleep(2)
			
			else:
				GPIO.output(akt1, GPIO.HIGH)
				GPIO.output(akt2, GPIO.HIGH)
				GPIO.output(akt3, GPIO.HIGH)
				print "alle aus"
				time.sleep(2)
	
Ich habe die Variable akt3 und möchte sie in folgenden Befehl intergrieren:

Code: Alles auswählen

GPIO.output(PIN_NUMMER, GPIO.HIGH)
Habe es wie oben zu sehen so versucht:

Code: Alles auswählen

GPIO.output(akt3, GPIO.HIGH)
und bekomme folgende Fehlermeldung rausgeschmissen:

Traceback (most recent call last):
File "fertig/processor.py", line 564, in <module>
GPIO.output(akt2, GPIO.HIGH)
ValueError: The channel sent is invalid on a Raspberry Pi


2. Wollte ich noch fragen ob es die Möglichkeit gibt in eine bestimmte Zeile einer Datei zu schreiben.

und 3. und letztens würde ich mich über Tipps freuen den Code etwas zu verkürzen.
60 Zeilen pro Pin und dass ohne Speicherung sind doch ziemlich viel ^^


Mir fehlt es wohl noch an einigen Basics, weis allerdings nicht nach was ich am besten suchen soll.
Betreibe eher Learning by doing und werde nachdem dieses "Großprojekt" abgeschlossen ist nicht mehr all zu viel mit Python machen, weshalb ich nicht unbedingt Lust hab jetzt Tagelang Basics zu pauken...

Hoffe ihr habt ein paar Tipps für mich :)

mfg
Fenestro
BlackJack

@fenestro: Das ist ja jetzt grundsätzlich erst einmal kein Problem eine Variable statt eines festen Wertes einzusetzen, sondern dass der Wert in der Datei offenbar falsch ist, weil es kein gültiger Wert für einen Pin ist.

Bezüglich des Verkürzens: Da wird in vielen Zweigen ja das gleiche gemacht. Eigentlich sind *alle* fast gleich. Die unterscheiden sich ja nur durch das zweite Argument bei den `output()`-Aufrufen und ein Wort im Ausgabetext. Da würde man sinnvollerweise die Bedingungen in *einem* ``if`` zusammenfassen und nicht für jede Teilbedingung ein neues ``if``/``else`` schreiben, und aufgrund der Bedingung nur die beiden Unterschiede an Namen binden und die dann danach in den 5 Zeilen verwenden die in jedem Zweig stehen, aber eigentlich nur einmal benötigt werden.

Oh, und zeig bitte Code der zum Problem passt, denn da wo Du den syntaktisch falschen Kommentar gesetzt hast, dass dort das Problem ist, haben wir eine Codezeile die niemals ausgeführt werden kann weil die Bedingung ``a[akt1] == "1"`` niemals zutreffen kann. In der Liste `a` befinden sich zu dem Zeitpunkt ganze Zahlen und es gibt keine ganze Zahl die gleich irgendeiner Zeichenkette ist.
fenestro
User
Beiträge: 13
Registriert: Sonntag 20. Oktober 2013, 00:33

doch doch das klappt,
das Problem war dass es zwei verschiedene id Typen gab, die die ich für die Zeichenreihenfolge in der Datei verwendet habe und die Pin Nummern. Ich habe die selbe verwendet, hab jetzt ne Funktion geschrieben die dass konvertiert und somit ist das Problem gelöst.

Hoffe irgendjemand hat noch ne Antwort auf Frage 2 parat.

Danke für die Hilfe jedenfalls :D
BlackJack

@fenestro: Zu Frage 2: Nein so allgemein ist das nicht möglich.
fenestro
User
Beiträge: 13
Registriert: Sonntag 20. Oktober 2013, 00:33

Das hätte ich mir fast schon gedacht...

ohne eine solche Funktion ist mein Script jedoch hinfällig.
Hast du einen Lösungsansatz für mich?
U.u. paar Funktionen die mir weiterhelfen könnten?
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@fenestro: Wie BlackJack schon sagte: "... so allgemein [...] nicht ..." Das heißt aber nicht, dass es sonderlich kompliziert wäre. Ich würde dazu die Datei Zeile für Zeile einlesen und gleich wieder Zeile für Zeile in eine neue Datei schreiben. Ist die bedingte Zeile erreicht, schreibe ich die gewünschte neue Zeile und fahre dann mit den restlichen Zeilen fort. Danach benenne ich die neue Datei mit dem Namen der eingelesenen Datei um.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@fenestro: Den Pfadangaben nach scheint es sich um eine Webanwendung zu handeln — da würde ich mal eine Datenbank vorschlagen.
fenestro
User
Beiträge: 13
Registriert: Sonntag 20. Oktober 2013, 00:33

ist richtig ja,
die von mir gewünschte Aufgabe war jedoch bei PHP mit Textdateien einfacher zu lösen,
außerdem finde ich es praktischer, da man viel einfacher etwas von Hand ändern kann oder bestimmt konfigurierte Dateien einspielen kann.

@BlackJack
Da fehlt mir wohl noch Theoretisches wissen dazu. :(
Hoffe mal das Internet spuckt irgendwas brauchbares aus...
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@fenestro: Die Methoden, die Du auf file objects anwenden kannst, müssten Dir IMHO alles, das Du brauchst, zur Verfügung stellen.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@fenestro: Was war denn bei PHP einfacher? Auch in PHP kann man im allgemeinen nicht gezielt eine Zeile in einer Textdatei überschreiben. Das hat letztendlich nichts mit der Programmiersprache zu tun, sondern wie auf modernen Dateisystemen Textdateien gespeichert sind: eine lineare Folge von Bytes.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hab' mal was gebastelt:

Code: Alles auswählen

def insert_line(file_, content, line_no=None, line=None):
    file_.seek(0)
    for idx, item in enumerate(file_):
        yield item
        if idx + 1 == line_no or item.strip('\n') == line:
            yield '{}\n'.format(content)

Code: Alles auswählen

In [7]: cat test
1
2
4

In [8]: t = open('test', 'r')

In [9]: new_t = open('new_test', 'w')

In [10]: new_t.writelines(insert_line(t, '3', line_no=2))

In [11]: new_t.close()

In [12]: cat new_test
1
2
3
4

In [13]: mv new_test test
mv: „test“ überschreiben? j

In [14]: t = open('test', 'r')

In [15]: new_t = open('new_test', 'w')

In [16]: new_t.writelines(insert_line(t, '5', line='4') 

In [17]: new_t.close()

In [18]: cat new_test
1
2
3
4
5
Natürlich müssen die Dateien noch sauber geöffnet, geschlossen und umbenannt werden, hab' ich jetzt aber keine Lust mehr... ;-)

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Warum das `seek()` am Anfang? Und das die Funktion im Grunde zwei verschiedene Dinge macht ist IMHO auch nicht schön.

`enumerate()` kann man auch einen optionalen Startwert geben. Ich fänd als API aber besser es wie beim Slicing zu machen so dass die Zahl nicht die Zeile sondern den „Zwischenraum” angibt. Dann könnte man das auch so schreiben, dass man eine Zeile vor der ersten Zeile einfügen kann.

Wobei ich die Aufgabe mit der Zeilen*nummer* wahrscheinlich mit `itertools.islice()` für den Teil vor der Zeile gelöst hätte, statt mit `enumerate()`.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

BlackJack hat geschrieben:Warum das `seek()` am Anfang? Und das die Funktion im Grunde zwei verschiedene Dinge macht ist IMHO auch nicht schön.
Das `seek()` hab' ich vergessen, war nur zum Testen, damit ich nicht jedesmal die Datei neu öffnen muss. Und dass die Funktion zwei verschiedene Optionen bedient ist nicht schön, stimmt. Nachdem ich nicht weiß, ob fenestro die Zeilennummer oder den Zeileninhalt zum Einfügen verwenden möchte, habe ich einfach mal beides berücksichtigt.

Hab's jetzt mal so aufgeteilt:

Code: Alles auswählen

def insert_before_index(file_, index, content):
    content = '{}\n'.format(content)
    return itertools.chain(
        itertools.islice(file_, index), (content,), file_
    )

def insert_before_text(file_, text, content):
    content = '{}\n'.format(content)
    text = '{}\n'.format(text)
    file_ = list(file_)
    index = file_.index(text)
    return file_[:index] + [content] + file_[index:]
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@mutetella: warum verwendest Du für die zweite Funktion nicht auch »itertools«:

Code: Alles auswählen

def insert_before_text(file_, text, content):
    content = '{}\n'.format(content)
    text = '{}\n'.format(text)
    return itertools.chain(
        itertools.takewhile(text.__ne__, file_), (content,text), file_
    )
fenestro
User
Beiträge: 13
Registriert: Sonntag 20. Oktober 2013, 00:33

Vielen vielen Dank!

Ich hätte zwar nur schreiben nach Zeilennummer gebraucht aber lieber zu viel als zu wenig :)
Werde das gleich nach der Arbeit ausprobieren.

Mfg
Fenestro
fenestro
User
Beiträge: 13
Registriert: Sonntag 20. Oktober 2013, 00:33

Irgendwas klappt da nicht ganz :(
Speicherung erfolgt, die Datei sieht dann aber statt

Code: Alles auswählen

0
1
1
1
so aus:

Code: Alles auswählen

1
0
1
1
1

Habs u.a. so versucht:

Code: Alles auswählen


import itertools
import os


def insert_line(file_, content, line_no=None, line=None):

    for idx, item in enumerate(file_):
        yield item
        if idx + 1 == line_no or item.strip('\n') == line:
            yield '{}\n'.format(content)
	

file = open('/var/www/lol.txt', 'r')
file_new = open('/var/www/lol_new.txt', 'w')
file_new.writelines(insert_line(file, '0', line_no=1))
file_new.close()

os.rename('/var/www/lol_new.txt','/var/www/lol.txt')

Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Nun deine Erwartung ist falsch, denn `enumerate` beginnt bei "0" und damit auch die Zeilennummern/-indizes.

Der Code hat aber tatsaechlich einen Fehler, da man nicht vor der ersten Zeile (Nummer 0) einfuegen kann, selbst wenn man die richtigen Indizes nutzt.
Ungetestet: Verschiebe Zeile 9 hinter den `if`-Block.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Die Version, die Du da verwendest, fügt hinter die gewünschte Zeile etwas an, Du möchtest davor einfügen. Lies Dir die Beiträge, die zwischen meiner ersten und der letzten Version ausgetauscht wurden, nochmals durch!

Code: Alles auswählen

def insert_before_index(file_, index, content):
    content = '{}\n'.format(content)
    return itertools.chain(
        itertools.islice(file_, index), (content,), file_
    )
Wenn Deine Datei so

Code: Alles auswählen

1
1
1
aussieht und Du vor die erste Zeile eine '0' einfügen möchtest, dann gehst Du folgendermaßen vor:

Code: Alles auswählen

def insert_line(filename, index, content):
    tmp_filename = '{}.tmp'.format(filename)
    with open(filename, mode='r') as orig_file:
        with open(tmp_filename, mode='w') as tmp_file:
            try:
                tmp_file.writelines(
                    insert_before_index(orig_file, index, content)
                )
            except Exception:
                os.remove(tmp_file)
                raise
    shutil.move(tmp_filename, filename)

Code: Alles auswählen

In [8]: cat test
1
1
1

In [9]: insert_line('test', 0, '0')

In [10]: cat test
0
1
1
1
Noch zur Erklärung:
  • Python beginnt die Index-Nummerierung bei 0, d. h. das erste Element ist nicht die 1, sondern die 0.
  • Öffne Dateien wenn irgend möglich mit dem with statement. Damit stellst Du sicher, dass die Datei auch im Falle eines Fehlers ordnungsgemäß geschlossen wird.
  • Innerhalb des try:...except:...Blocks wird zuerst versucht, die gewünschte Datei temporär zu schreiben. Gelingt dies aus irgendeinem Grunde nicht, wird die temporäre Datei gelöscht und der Fehler ausgelöst. Geht alles gut, wird die ursprüngliche Datei mit der erfolgreich erstellten neuen Datei ersetzt.


mutetella


EDIT: Und verwende `file` nicht als Namen, da Du dadurch die built-in Funktion file überschreibst.
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
fenestro
User
Beiträge: 13
Registriert: Sonntag 20. Oktober 2013, 00:33

Ich glaub ihr habt etwas falsch verstanden.
ich möchte nicht davor sondern stattdessen einsetzen.

mfg
fenestro

//edit:
hab folgenden Code geschrieben:

Code: Alles auswählen


import os



with open('/var/www/lol.txt', 'r') as input_file, open('/var/www/lol_new.txt', 'w') as output_file:

	i = 0
	while 1:
		i = i+1
		if i == 18:
			break
				
		if i == 2:
			output_file.write('1\n')
		else:
			output_file.write(i-1)		
			
	os.rename('/var/www/lol_new.txt','/var/www/lol.txt')	
	

bekomme aber den Error

output_file.write(i-1)
TypeError: expected a character buffer object
Sirius3
User
Beiträge: 17753
Registriert: Sonntag 21. Oktober 2012, 17:20

@fenestro: Du kannst auch keine Zahlen in Dateien schreiben, sondern nur Bytes. Dein Code benutzt input_file ja auch gar nicht. Wenn Du eine Zahl einfach hochzählen willst, dann benutz doch eine »for«-Schleife und keine »while«-Schleife.

Warum erweiterst Du nicht einfach mutetellas Beispiel:

Code: Alles auswählen

def substitute_with(iterable, start, stop, content):
    iterable = iter(iterable)
    return itertools.chain(
        itertools.islice(iterable, start), content, itertools.islice(iterable, stop-start, None)
    )


def substitute_lines(filename, start, stop, content):
    tmp_filename = '{}.tmp'.format(filename)
    with open(filename, mode='r') as orig_file:
        with open(tmp_filename, mode='w') as tmp_file:
            try:
                tmp_file.writelines(
                    substitute_with(orig_file, start, stop, content)
                )
            except Exception:
                os.remove(tmp_file)
                raise
    shutil.move(tmp_filename, filename)

substitute_lines('lol.txt', 2,3, ['1\n'])
Antworten