Liste und Ausgabe

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
Benutzeravatar
Dirki
User
Beiträge: 69
Registriert: Donnerstag 23. Juni 2016, 16:11

Hallo nochmal ;)

Ich habe das Buch mal beiseite gelegt und gedacht ich setze mal ein bisschen meines noch nicht vorhandenen Wissens in die Praxis um und versuche mich an einem kleinen Projekt.

Tatsächlich klappt schon einiges, aber etwas was eigentlich einfach gehen soll bekomme ich nicht umgesetzt:

ich habe eine Liste:

Code: Alles auswählen

server =[["0","server1","server1.de","444"],
              ["1","Server-lokal", "server", "22"],
              ["2","Server-extern", "externeadresse.selfhost.eu", "32"]
         ]
jetzt möchte ich daraus ein Menü erstellen

die Anzahl der Server in der Liste erhalte ich mit:

Code: Alles auswählen

men = len(server)
Ich denke mal ich brauche eine for-schleife, aber wie muss die aussehen, das ich daraus ein Ansehnliches Menü ausgegeben bekomme?
Wenn einer von euch Antwortet, werde ihc mich ärgern, das ich nicht alleine darauf gekommen bin.

Also bitte ärgert mich! :wink:

Danke!
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Zuersmal ist es suspekt, dass du

- alles in Strings ausdrueckst. Portangaben sind sinnvoller gleich als Ganzzahlwerte.
- der erste Eintrag einfach nur eine laufende Nummer ist. So etwas macht man nicht, die gewinnt man.


Und dann kann das zB so aussehen:

Code: Alles auswählen

server =[["server1","server1.de", 444],
              ["Server-lokal", "server", 22],
              ["Server-extern", "externeadresse.selfhost.eu", 32]
         ]
for num, (name, host, port) in enumerate(server):
       print(num, name, host, port) # und hiermit kannst du dann auch dein Menu machen - was auch immer dazu getan werden muss.
Benutzeravatar
Dirki
User
Beiträge: 69
Registriert: Donnerstag 23. Juni 2016, 16:11

danke! danke! danke!

Ich werde es direkt mal testen.

Was die laufende Nummer und Ports betrifft hast du natürlich vollkommen recht, das wird natürlich geändert.

Edit:

Funktioniert super! Genau das was ich wollte. Ich kannte die Funktion noch nicht, kommt wohl erst später im Buch. ;)
Benutzeravatar
Dirki
User
Beiträge: 69
Registriert: Donnerstag 23. Juni 2016, 16:11

*grummel*

ich habe folgendes versucht:

Code: Alles auswählen

subprocess.call(["ssh", server[1][1], "-p", server[1][2]])
im Bezug auf der Liste:

Code: Alles auswählen

server =[["server1","server1.de", 444],
              ["Server-lokal", "server", 22],
              ["Server-extern", "externeadresse.selfhost.eu", 32]


Eigentlich bin ich der Meinung, das das vorhin schon mal funktioniert hat, aber wer weiß was ich da wieder gemacht habe. :(

Das Ganze soll eigentlich mal mit einer Funktion funktionieren.

Code: Alles auswählen

def connect(nr):
    subprocess.call(["ssh", server[nr][1], "-p", server[nr][2] ])
Ich hoffe ich habe mein Tipp-Konto noch nicht aufgebraucht.

Hat noch mal jemand einen Tipp für mich?
Pygoscelis papua
User
Beiträge: 206
Registriert: Freitag 13. März 2015, 18:36

Ich hoffe ich habe mein Tipp-Konto noch nicht aufgebraucht.
Nein hast du nicht :)
Könntest du die Fehlermeldung posten?
Ich glaube man darf in subprocess.call() in der liste die als Argument verwendet wird keine integer schreiben:

Code: Alles auswählen

>>>import subprocess
>>> subprocess .call([1, 2, 3])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.5/subprocess.py", line 560, in call
    with Popen(*popenargs, **kwargs) as p:
  File "/usr/lib64/python3.5/subprocess.py", line 950, in __init__
    restore_signals, start_new_session)
  File "/usr/lib64/python3.5/subprocess.py", line 1467, in _execute_child
    executable = os.fsencode(executable)
  File "/usr/lib64/python3.5/os.py", line 820, in fsencode
    raise TypeError("expect bytes or str, not %s" % type(filename).__name__)
TypeError: expect bytes or str, not int
Am besten wäre es wahrscheinlich, wenn du mal den ganzen Quelltext im Zusammenhang samt Ausgabe senden würdest
import this
hidden python features

JAVA = Just Another Vulnerability Announcement :D
Benutzeravatar
Dirki
User
Beiträge: 69
Registriert: Donnerstag 23. Juni 2016, 16:11

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-

# Module laden
import subprocess

# Serverliste
# Der Syntax kann aus den Beispielen entnommen werden,
# das Komma am ende der Zeile (ausser beim letzten Eintrag) darf nicht vergessen werden

# servername,serveradresse,port
server =[["Server1","server.de",444],
         ["Server-lokal", "server", 22],
         ["Server-extern", "server.selfhost.eu", 32]
         ]



# Funktionen
def connect(nr):
    subprocess.call(["ssh", server[1][1], "-p", server[1][2] ])

def menu():
    print("{0:<4}{1:<14}{2:<20}{3:<5}".format("Nr.", "Servername", "Adresse", "Port"))
    for num, (name, host, port) in enumerate(server):
        print("{0:<4}{1:<14}{2:<20}{3:<5}".format(num, name, host, port))




# Hauptprogramm
# subprocess.call(["ssh", server[1][1], "-p", server[1][2] ])
menu()
num = len(server)
aw = int(input("Bitte Servernummer eingeben:"))
if aw <= num - 1:
    print("verbinden") # zum testen
    subprocess.call(["ssh", server[1][1], "-p", server[1][2]]) #Das soll in Zukunft über Variablen und die Funktion oben funktionieren, der Eintrag ist erstmal zum testen
else:
    print("nicht verbinden") #zum testen
Wie gesagt, das ist mein erstes Projekt nach 10 Tagen Python-Studium. Einiges wird sicher eleganter zu lösen sein, aber irgendwo mit muss man ja anfangen. ;)
Zuletzt geändert von Anonymous am Freitag 1. Juli 2016, 21:52, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Pygoscelis papua
User
Beiträge: 206
Registriert: Freitag 13. März 2015, 18:36

also bei mir hats funktioniert nachdem ich

Code: Alles auswählen

subprocess.call(["ssh", str(server[aw][1]), "-p", str(server[aw][2])])
(Zeile 39)
eingegeben habe.
Zuersmal ist es suspekt, dass du

- alles in Strings ausdrueckst. Portangaben sind sinnvoller gleich als Ganzzahlwerte
@ __deets__ warum, wenn man doch nur die string-werte verwendet?
Ist das nicht sogar schneller?
import this
hidden python features

JAVA = Just Another Vulnerability Announcement :D
Benutzeravatar
Dirki
User
Beiträge: 69
Registriert: Donnerstag 23. Juni 2016, 16:11

Ich sehe schon, es gibt noch viel zu lernen.

Danke dir für deine Antwort. Das teste ich nachher direkt wenn ich wieder am Rechner bin.:-)
BlackJack

@Dirki: Einige von den Kommentaren im Quelltext sollten da nicht wirklich stehen. Zum Beispiel Hinweise zur Syntax von Python, oder ``# Module laden`` und ``# Funktionen``. ``# Hauptprogramm`` solle da nicht stehen müssen, weil der Code dort, der das Hauptprogramm ausmacht üblicherweise in einer Funktion steht, die `main()` heisst. Kommentare sind dazu da um jemandem der Python-Code versteht, etwas zu erklären was nicht bereits im Code dort steht. Faustregel: Kommentare sollten sagen *warum* etwas gemacht wird, sofern das nicht offensichtlich ist, nicht *was* gemacht wird, denn das wird aus dem Code selbst ja schon offensichtlich.

Bei der `menu()`-Funktion würde ich erwarten das in dieser Funktion auch die Benutzerabfrage stattfindet und dem Aufrufer das Ergebnis als Rückgabewert geliefert wird.

Konstantennamen werden per Konvention komplett gross geschrieben (`SERVER`) und bei Containertypen die mehrere Werte enthalten, wählt man in der Regel die Mehrzahl von dem Namen der für ein Element passen würde, also `SERVERS`.

Namen sollte man nicht abkürzen solange das nicht allgemein gebräuchliche Abkürzungen sind. `num` und `aw` sind also keine guten Namen. `num` würde auch eher `length` heissen oder weniger allgemein `server_count`. Allerdings könnte man auf den Namen auch verzichten wenn man den Wert nur in der einen Stelle benötigt. Dort könnte man sich das ``- 1`` sparen wenn man nicht auch auf Gleichheit testen würde, sondern nur auf ``<``. Benutzer geben manchmal die komischsten Dinge ein, nur so zum Spass auch mal eine -100. Oder gar keine Zahl.

@Pygoscelis papua: Weil Portnummern vom Wesen her ganze Zahlen sind und es ist weniger verwirrend wenn die sich auch so verhalten. Das hier eine Zeichenkette benötigt wird, liegt ja nur an der Kommunikation mit der Aussenwelt über `subprocess`.
Benutzeravatar
Dirki
User
Beiträge: 69
Registriert: Donnerstag 23. Juni 2016, 16:11

Danke BlackJack für die zahlreichen Anregungen, Ich werde diese beherzigen und in meiner Doku ablegen, das ist viel Stoff :)
Mit weniger Kommentaren ist der Code direkt schicker. ;)
Einige Kommentare habe ich allerdings bewusst in den Code eingefügt, damit man mich nicht für den letzten Deppen hält, der die hälfte vergessen hat. ;)

Gute Nacht! Ich mach morgen weiter!

Wenn ich mit dem Programm fertig bin, kann ich das gerne hier nochmal posten.
Benutzeravatar
Dirki
User
Beiträge: 69
Registriert: Donnerstag 23. Juni 2016, 16:11

hm... Irgendwie habe ich hier schon irgendwo gelesen, dass globale Variablen böse sind, daher würde ich diese gerne vermeiden. Aber irgendwie gibt die funktion menu() nicht die Werte zurück, oder ich mache was anderes falsch.

@ Blackjack:
einige Änderungen konnte ich schon umsetzten. Bin heute allerdings immer nur kurz am PC.

Soweit ist jetzt der aktuelle Stand, wenn ich die globallen Variablen auskommentiere, bekomme ich folgende Fehlermeldung:
Traceback (most recent call last):
File "./xssh.py", line 31, in <module>
if srv_nr < counts :
NameError: name 'srv_nr' is not defined
[codebox=pycon file=Unbenannt.txt]
#!/usr/bin/python3
# -*- coding: utf-8 -*-

import subprocess

# Serverliste
# Der Syntax kann aus den Beispielen entnommen werden,
# das Komma am ende der Zeile (ausser beim letzten Eintrag) darf nicht vergessen werden

# servername,serveradresse,port
SERVERS =[["Server1","server.de",444],
["Server-lokal", "server", 22],
["Server-extern", "server.selfhost.eu", 32]
]

def connect(x):
subprocess.call(["ssh", str(SERVERS[x][1]), "-p", str(SERVERS[x][2])])

def menu():
#global srv_nr
#global counts
print("{0:<4}{1:<14}{2:<20}{3:<5}".format("Nr.", "Servername", "Adresse", "Port"))
for server_count, (name, host, port) in enumerate(SERVERS):
print("{0:<4}{1:<14}{2:<20}{3:<5}".format(server_count, name, host, port))
counts = len(SERVERS)
srv_nr = int(input("Bitte Servernummer eingeben: "))
return counts, srv_nr

menu()

if srv_nr < counts :
connect(srv_nr)
else:
print()
print("unültige Eingabe!")
print()
menu()
[/code]
Pygoscelis papua
User
Beiträge: 206
Registriert: Freitag 13. März 2015, 18:36

du musst in Zeile 29 schreiben:

Code: Alles auswählen

counts, srv_nr = menu()
nur so nebenbei: ich würde in der funktion connect nicht x als Argument verwenden, da wenn jemand die Funktion liest, er nicht gleich versteht
was x bedeutet. Man könnte als Argument vieleicht "server" oder so wählen,
import this
hidden python features

JAVA = Just Another Vulnerability Announcement :D
Benutzeravatar
Dirki
User
Beiträge: 69
Registriert: Donnerstag 23. Juni 2016, 16:11

Ahhhhhh! Himmel noch mal. Ist mir das unangenehm. Aber ich lasse mich durch Fehler nicht entmutigen. Ich lerne das *schakka!*

An die Namensgebung der Variablen arbeite ich noch.

Aber durch diese paar Zeilen Code und viele dumme Fragen und Fehler habe ich eine Menge von Euch gelernt.

Ganz im Ernst das ist das erste Forum was ich in den letzten Jahren freiwillig betreten habe. Ich bin euch echt dankbar. Ihr seid super hilfsbereit und stets konstruktiv in eurer Kritik und Anregungen. Danke vielmals dafür und für eure Geduld. Das könnte dank euch meine erste Programmiersprache sein die ich richtig lerne.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Dirki: jetzt kommt noch der Feinschliff, also nicht erschrecken, was man alles noch anders machen kann.

Listen sind dazu da, gleichartige Dinge zu sammeln. Die inneren Listen bestehen aber aus verschiedenartigen Dingen (Name, Addresse und Port). Dazu verwendet man typischerweise Tuple, oder noch besser NamedTuple. »connect« sollte gleich Server und Port als Argumente bekommen und nicht einen Index auf irgendeine Struktur. Warum liefert »menu« die Anzahl der Menüeinträge zurück? Diese Prüfung sollte gleich innerhalb der Menü-Funktion passieren. Denn die Ungültigkeitsprüfung im Hauptprogramm macht im Moment noch nicht viel Sinn.

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import subprocess
 
# Serverliste
# servername, serveradresse, port
SERVERS =[
    ("Server1", "server.de", 444),
    ("Server-lokal", "server", 22),
    ("Server-extern", "server.selfhost.eu", 32),
]
 
def connect(server, port):
    subprocess.call(["ssh", server, "-p", str(port)])
 
def menu(servers):
    print("{0:<4}{1:<14}{2:<20}{3:<5}".format("Nr.", "Servername", "Adresse", "Port"))
    for index, (name, host, port) in enumerate(servers, 1):
        print("{0:<4}{1:<14}{2:<20}{3:<5}".format(index, name, host, port))
    while True:
        try:
            index = int(input("Bitte Servernummer eingeben: "))
        except ValueError:
            pass
        else:
            if 0 < index <= len(servers):
                return servers[index - 1]

def main():
    name, host, port = menu(SERVERS)
    connect(host, port)

if __name__ == '__main__':
    main()
Benutzeravatar
Dirki
User
Beiträge: 69
Registriert: Donnerstag 23. Juni 2016, 16:11

Die meisten Änderungen verstehe ich, aber ab Zeile 29 verstehe ich das leider nicht mehr. Kannst das bei Gelegenheit mal genauer erklären?
Antworten