Hi Leute,
Ich bin dabei einen Wrapper zu schreiben für die PS Tools von Windows, nun bin ich noch lange nicht fertig, doch ich
wollte mal wissen, wie man sowas normalerweise macht, denn wie ihr an meinem Codesnippet sehen
könnt, treten bei mir viele Dictionaries und if-else-Kaskaden auf, siehe psexec(). Also wie macht man sowas eleganter?
Danke im voraus.
Liebe Grüße,
Jonas
Edit: @Codesnippet:
TESTPATH in der main() ist durch "__file__" zur ersetzen,
ich hatte nur einen lokalen Testpfad für Tests in IDLE.
Geschickte Lösung: Dictionaries/ if-else-Kaskaden
@jonas: Das sieht mir nach ein bisschen viel "Magie" und Typtesterei aus. Ich würde da wohl eher mit objektorientierter Programmierung herangehen, oder zumindest die Aktionen nicht vom Typ der Argumente abhängig machen, sondern die Information was zu tun ist, bei den Werten in `EXEC_PARAMS` hinterlegen. Denn eigentlich sollte das doch für die einzelnen Argumente dort eindeutig sein!? Bei 'password' dürfte doch wohl eine Zeichenkette gefragt sein und weder ein Wahrheitswert noch eine Priorität!?
Ansonsten könntest Du ein paar "list comprehensions" durch Generatorausdrücke ersetzen. Also einfach die eckigen Klammern weglassen.
Es gibt `os.path.join()`.
Bei `psexec()` könnte man auch bei diesem Ansatz einiges verbessern. Da steht sehr oft der Zugriff ``kwargs[key]``, was man vermeiden könnte wenn man gleich über Schlüssel *und* Wert iteriert. Ist das erste ``if`` wirklich notwendig? Dadurch werden nicht existierende Argumentnamen einfach ignoriert. Man könnte ``EXEC_PARAMS[key]`` doch auch einfach einen `KeyError` auslösen lassen. Dann weiss der Aufrufer dass er was falsch gemacht hat. Auf jeden Fall sollte man den Aufruf von `has_key()` durch den ``in``-Operator ersetzen. Das ist besser lesbar und zukunftssicherer -- die Methode ist nämlich "deprecated".
Warum ist das `PRIORITY`-Dictionary im `EXEC_PARAMS`-Dictionary? Das ist eine unnötige Indirektion. Da der Fall sowieso in einem ganz eigenen ``if``-Zweig behandelt wird, hätte man das verwirrende ``EXEC_PARAMS[key][kwargs[key]]`` auch wesentlich einfacher schreiben können. Einfach als ``PRIORITY[value]`` wenn in der Schleife nicht nur über den Schlüssel iteriert würde. Das ist wesentlich übersichtlicher finde ich.
Nimmt eine der Optionen von den PS_TOOL eigentlich eine Zahl als Argument entgegen? Falls ja, ist Dir das hier klar!?
Also ``psexec(run_on_cpu=1)`` hat deshalb eventuell nicht den gewünschten Effekt.
Im `False`-Fall eine leere Zeichenkette zur Liste hinzuzufügen ist vielleicht auch keine gute Idee. Das ist bei `subprocess` trotzdem ein Argument und eines was die Programme da vielleicht nicht erwarten.
Warum Du die ``if``\s so tief verschachtelt hast, ist mir auch nicht so ganz klar!? Wonach hast Du denn entschieden in einem ``else``-Zweig mit einem ``if`` zu beginnen statt da ein ``elif`` draus zu machen?
Den Typtest solltest Du mit `isinstance()` machen. Da kann man als zweites Argument auch ein Tupel mit mehreren Typen angeben. Allerdings würde ich nicht auf `list` und `tuple` testen sondern auf `basestring` und die Zweige umkehren. Es ist nämlich viel wahrscheinlicher das jemand dort ein anderes "iterable" als Liste oder Tupel übergibt als dass jemand einen eigenen Untertyp von Zeichenketten verwendet.
Ansonsten könntest Du ein paar "list comprehensions" durch Generatorausdrücke ersetzen. Also einfach die eckigen Klammern weglassen.
Es gibt `os.path.join()`.
Bei `psexec()` könnte man auch bei diesem Ansatz einiges verbessern. Da steht sehr oft der Zugriff ``kwargs[key]``, was man vermeiden könnte wenn man gleich über Schlüssel *und* Wert iteriert. Ist das erste ``if`` wirklich notwendig? Dadurch werden nicht existierende Argumentnamen einfach ignoriert. Man könnte ``EXEC_PARAMS[key]`` doch auch einfach einen `KeyError` auslösen lassen. Dann weiss der Aufrufer dass er was falsch gemacht hat. Auf jeden Fall sollte man den Aufruf von `has_key()` durch den ``in``-Operator ersetzen. Das ist besser lesbar und zukunftssicherer -- die Methode ist nämlich "deprecated".
Warum ist das `PRIORITY`-Dictionary im `EXEC_PARAMS`-Dictionary? Das ist eine unnötige Indirektion. Da der Fall sowieso in einem ganz eigenen ``if``-Zweig behandelt wird, hätte man das verwirrende ``EXEC_PARAMS[key][kwargs[key]]`` auch wesentlich einfacher schreiben können. Einfach als ``PRIORITY[value]`` wenn in der Schleife nicht nur über den Schlüssel iteriert würde. Das ist wesentlich übersichtlicher finde ich.
Nimmt eine der Optionen von den PS_TOOL eigentlich eine Zahl als Argument entgegen? Falls ja, ist Dir das hier klar!?
Code: Alles auswählen
In [112]: 1 == True
Out[112]: True
In [113]: 0 == False
Out[113]: True
Im `False`-Fall eine leere Zeichenkette zur Liste hinzuzufügen ist vielleicht auch keine gute Idee. Das ist bei `subprocess` trotzdem ein Argument und eines was die Programme da vielleicht nicht erwarten.
Warum Du die ``if``\s so tief verschachtelt hast, ist mir auch nicht so ganz klar!? Wonach hast Du denn entschieden in einem ``else``-Zweig mit einem ``if`` zu beginnen statt da ein ``elif`` draus zu machen?
Den Typtest solltest Du mit `isinstance()` machen. Da kann man als zweites Argument auch ein Tupel mit mehreren Typen angeben. Allerdings würde ich nicht auf `list` und `tuple` testen sondern auf `basestring` und die Zweige umkehren. Es ist nämlich viel wahrscheinlicher das jemand dort ein anderes "iterable" als Liste oder Tupel übergibt als dass jemand einen eigenen Untertyp von Zeichenketten verwendet.
WoW Blackjack ich staune immer wieder wie schnell man von dir einen hochinformativen Beitrag vor die Nase bekommt
Ich habe noch nicht so ganz verstanden, was ich mit "os.path.join()" anfangen soll? Suchen der PS Tools funktioniert doch super?
@psexec:
Jo, dachte ich mir schon, dass es hier einiges zu verbessern gibt.
Habe länger nix mehr gemacht mit Python, bin gerade dabei mich
wieder mehr reinzufuchsen
@Codeschnippsel:
Nee, das war mir so nicht klar, aber danke für den Hinweis
@leere Zeichenkette:
Also kein Problem.
@if/Verschachtelung:
Ich weiß nicht genau, warum ich das so gemacht habe,
hat sich irgendwie so ergeben..
@isinstance():
Wird eingebaut.
@BlackJack:
Vielen Dank nochmal
Liebe Grüße,
Jonas
@Code:
Wird morgen nochmal verbessert geuppt,
muss heute noch bisschen komplexe Zahlen,
vollständige Induktion, Restklassen und so
ein Kram für Mathe lernen... (-.-)
Ich habe noch nicht so ganz verstanden, was ich mit "os.path.join()" anfangen soll? Suchen der PS Tools funktioniert doch super?
@psexec:
Jo, dachte ich mir schon, dass es hier einiges zu verbessern gibt.
Habe länger nix mehr gemacht mit Python, bin gerade dabei mich
wieder mehr reinzufuchsen
@Codeschnippsel:
Nee, das war mir so nicht klar, aber danke für den Hinweis
@leere Zeichenkette:
Code: Alles auswählen
>>> "".join(["","hello","","you",""])
'helloyou'
@if/Verschachtelung:
Ich weiß nicht genau, warum ich das so gemacht habe,
hat sich irgendwie so ergeben..
@isinstance():
Wird eingebaut.
@BlackJack:
Vielen Dank nochmal
Liebe Grüße,
Jonas
@Code:
Wird morgen nochmal verbessert geuppt,
muss heute noch bisschen komplexe Zahlen,
vollständige Induktion, Restklassen und so
ein Kram für Mathe lernen... (-.-)
Hi,
ich bin es nochmal, ich habe nun ein anderes Problem und
zwar habe ich in diesem Codestück ein seltsames Verhalten, von dem ich nicht weiß,
wieso?
Eigentlich sollte die Ausgabe sein:
stattdessen erhalte ich:
Ich weiß leider nicht, wieso und hoffe, ihr könnt mir helfen.
Lg, Jonas
ich bin es nochmal, ich habe nun ein anderes Problem und
zwar habe ich in diesem Codestück ein seltsames Verhalten, von dem ich nicht weiß,
wieso?
Eigentlich sollte die Ausgabe sein:
Code: Alles auswählen
-keyH 1 2 -keyF example
Code: Alles auswählen
-keyE 1 2 -keyE example
Lg, Jonas
@jonas: Freie Variablen in Funktionen werden nachgeschlagen wenn die Funktion aufgerufen wird und nicht wenn sie erzeugt werden. Das `parameter` in den ``lambda``\s hat damit in allen den gleichen Wert nämlich was in der `make_function_dictionary()` als Letztes an diesen Namen gebunden wurde.
@jonas: Noch ein paar Anmerkungen:
Statt eine Liste mit den Elementen von `dictionary` in der `create_command()` zu erzeugen und darüber zu iterieren ist `iteritems()` besser.
Warum prüfst Du ob `key` im Dictionary ist um gegebenenfalls einen `KeyError` auszulösen, wo das doch das normale Verhalten ist, wenn man einfach darauf zugreift? Und auch hier wird wieder unnötigerweise eine Liste mit den Schlüsseln erzeugt um dann in linearer Zeit zu schauen ob der Schlüssel da drin enthalten ist. Schlüssel kann man auch ganz einfach mit ``key in dictionary`` überprüfen und das geht viel schneller.
`inputtype` und `func` könnte man auch mittels "sequence unpacking" zuweisen, dann spart man sich eine Zeile und unnötige Indexzugriffe.
Der Formatcode '%s' sorgt dafür dass das Objekt in eine Zeichenkette umgewandelt wird, da muss man nicht selber vorher `str()` verwenden.
Warum hängst Du den `SEPARATOR` überall an statt ihn zum "joinen" zu verwenden?
`make_function_dictionary()` ist insgesamt ein wenig komisch. Das `typedictionary` wird bei jedem Schleifendurchlauf neu erstellt und auch die ganzen ``lambda``-Funktionen darum werden immer wieder neu erstellt. Und `inputtype` in dem Dictionary entspricht ja genau dem Key mit dem Du dann darauf zugreifst. Ich würde das Dictionary da rausziehen und nur die Typen auf die Funktionen abbilden. Und zwar auf Funktionen mit *zwei* Argumenten: Wert und `parameter`. Den kann man dann mit `functools.partial` in der Schleife an den aktuellen Parameter binden.
Auf Wahrheitswerte sollte man übrigens nicht mit ``is`` Testen. Das kann funktionieren, muss es aber nicht.
Statt eine Liste mit den Elementen von `dictionary` in der `create_command()` zu erzeugen und darüber zu iterieren ist `iteritems()` besser.
Warum prüfst Du ob `key` im Dictionary ist um gegebenenfalls einen `KeyError` auszulösen, wo das doch das normale Verhalten ist, wenn man einfach darauf zugreift? Und auch hier wird wieder unnötigerweise eine Liste mit den Schlüsseln erzeugt um dann in linearer Zeit zu schauen ob der Schlüssel da drin enthalten ist. Schlüssel kann man auch ganz einfach mit ``key in dictionary`` überprüfen und das geht viel schneller.
`inputtype` und `func` könnte man auch mittels "sequence unpacking" zuweisen, dann spart man sich eine Zeile und unnötige Indexzugriffe.
Der Formatcode '%s' sorgt dafür dass das Objekt in eine Zeichenkette umgewandelt wird, da muss man nicht selber vorher `str()` verwenden.
Warum hängst Du den `SEPARATOR` überall an statt ihn zum "joinen" zu verwenden?
`make_function_dictionary()` ist insgesamt ein wenig komisch. Das `typedictionary` wird bei jedem Schleifendurchlauf neu erstellt und auch die ganzen ``lambda``-Funktionen darum werden immer wieder neu erstellt. Und `inputtype` in dem Dictionary entspricht ja genau dem Key mit dem Du dann darauf zugreifst. Ich würde das Dictionary da rausziehen und nur die Typen auf die Funktionen abbilden. Und zwar auf Funktionen mit *zwei* Argumenten: Wert und `parameter`. Den kann man dann mit `functools.partial` in der Schleife an den aktuellen Parameter binden.
Auf Wahrheitswerte sollte man übrigens nicht mit ``is`` Testen. Das kann funktionieren, muss es aber nicht.
Code: Alles auswählen
from functools import partial
SEPARATOR = ' '
def make_function_dictionary(dictionary):
converters = {
bool: lambda p, v: str(p) if v else '',
int: lambda p, v: str(p) + SEPARATOR + str(v),
str: lambda p, v: str(p) + SEPARATOR + str(v),
tuple: lambda p, v: str(p) + SEPARATOR + SEPARATOR.join(map(str, v))
}
return dict((k, [t, partial(converters[t], p)])
for k, (t, p) in dictionary.iteritems())
def create_command(dictionary, **keywords):
command = list()
for key, value in keywords.iteritems():
inputtype, func = dictionary[key]
if isinstance(value, inputtype):
command.append(func(value))
else:
raise ValueError('%s is not type of %s' % (value, inputtype))
return SEPARATOR.join(command)
def main():
notready = {
'keyE': [bool, '-keyE'],
'keyF': [str, '-keyF'],
'keyG': [int, '-keyG'],
'keyH': [tuple, '-keyH']
}
notready = make_function_dictionary(notready)
print create_command(notready, keyE=False, keyF='example', keyH=(1, 2))
if __name__ == "__main__":
main()
Das ist toll, super!
Ich danke dir wirklich sehr, ohne dich hätte ich das nicht
geschafft..
Ich muss noch viel Lernen über Programmieren mit Python und
allgemein schätze ich, aber ich denke das wird
Also vielen Dank noch mal!
Lg, Jonas
Ich danke dir wirklich sehr, ohne dich hätte ich das nicht
geschafft..
Ich muss noch viel Lernen über Programmieren mit Python und
allgemein schätze ich, aber ich denke das wird
Also vielen Dank noch mal!
Lg, Jonas
@jonas:
Oder Du sprichst mit ctypes die WinAPI direkt an. Je nach Deiner Zielsetzung ist das vllt. sogar der einfachere Weg.
In Sachen Prozessmanagement wird das allerdings sehr schnell Windows-versionspezifisch, gerade wenn Du Funktionen aus psapi.dll und ntdll.dll benötigst. Die WinAPI ist relativ gut dokumentiert (auch ohne MSDN-Zugang), wobei ntdll.dll nicht mehr zur offiziellen "öffentlichen" API gehört, sondern Microsoft als interne Userland->Kernel-API dient. Allerdings lassen sich bestimmte Dinge nur hierüber einsehen, daher verwundert es auch nicht, das die sysinternals-Leute (von denen stammen die pstools) hiervon ordentlich Gebrauch machen.
Damit fallen dann auch Abhängigkeiten wie DDK oder .NET-Installation weg.
Oder Du sprichst mit ctypes die WinAPI direkt an. Je nach Deiner Zielsetzung ist das vllt. sogar der einfachere Weg.
In Sachen Prozessmanagement wird das allerdings sehr schnell Windows-versionspezifisch, gerade wenn Du Funktionen aus psapi.dll und ntdll.dll benötigst. Die WinAPI ist relativ gut dokumentiert (auch ohne MSDN-Zugang), wobei ntdll.dll nicht mehr zur offiziellen "öffentlichen" API gehört, sondern Microsoft als interne Userland->Kernel-API dient. Allerdings lassen sich bestimmte Dinge nur hierüber einsehen, daher verwundert es auch nicht, das die sysinternals-Leute (von denen stammen die pstools) hiervon ordentlich Gebrauch machen.
Damit fallen dann auch Abhängigkeiten wie DDK oder .NET-Installation weg.