There should be one-- and preferably only one --obvious way to do it. 1)
Folgende Variablen sind gegeben:
IP="192.168.5.55" PORT="80" DNSname="www.example.com" HWname="lnx-kluftinger"
Folgende Ausgabe wollen wir erreichen:
* 192.168.5.55:80 -- www.example.com -- lnx-kluftinger
There is more than one way to do it … oh, das war doch eigentlich das Motto von Perl … naja, manchmal schlägt das auch bei Python zu
Diese 3 Methoden gab es auch schon bei früheren Python2 Versionen, sind aber bis heute noch gültig und auch nicht abgekündigt (Stand Python 3.7, 2019-03)
print ("* " + IP + ":" + PORT + " -- " + DNSname + " -- " + HWname) print ("* %s:%s -- %s -- %s" % ( IP, PORT, DNSname, HWname )) print ("* %(a)s:%(b)s -- %(c)s -- %(d)s" % {'a':IP,'b': PORT, 'c': DNSname, 'd':HWname})
Die Methoden mit .format
ist bei Python2.7 dazu gekommen. Auch print()
mit Klammern als Funktion ist bei 2.7 schon möglich, seit Python 3 geht es nicht mehr ohne Klammern.
print ("* {}:{} -- {} -- {}".format( IP, PORT, DNSname, HWname )) print ("* {1}:{2} -- {3} -- {0}".format( HWname, IP, PORT, DNSname )) print ("* {a}:{b} -- {c} -- {d}".format(a=IP, b=PORT, c=DNSname, d=HWname))
Seit Python 3.6 geht es noch einfacher, f vor den String schreiben, die Variablen direkt in die geschweiften Klammern …
print (f"* {IP}:{PORT} -- {DNSname} -- {HWname}")
In den meisten Fällen ist das für mich (ab Python 3.6) auch der offensichtlichste Weg, Strings zu formatieren. Damit stimmt für mich das Python ZEN also wieder .
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch. 2)
Hier ein sehr kleines Script "wuerfel.py" das einfach nur einen Würfelwurf mit dem sechs-seitigen Würfel simuliert.
#!/usr/bin/env python3 """einmal wuerfeln, bisher nur mit d6""" def d6wuerfeln(): """d6wuerfeln - ein wurf mit dem D6""" import random seiten = (1, 2, 3, 4, 5, 6) return random.choice(seiten) if __name__ == '__main__': print(d6wuerfeln())
Und hier der dazupassende Unit-Test "test_wuerfel.py"
#!/usr/bin/env python3 """teste das wuerfel script""" import unittest import wuerfel class WuerfelTestCase(unittest.TestCase): """teste wuerfel modul""" def test_ist_integer(self): """es sollen nur integer zurueck gegeben werden""" self.assertTrue(isinstance(wuerfel.d6wuerfeln(), int), "kein Integer") def test_kleinergleich6(self): """die zahl soll kleiner oder gleich 6 sein""" self.assertTrue(wuerfel.d6wuerfeln() <= 6, "groesser als 6") def test_groessergleich1(self): """die zahl soll groesser oder gleich 1 sein""" self.assertTrue(wuerfel.d6wuerfeln() >= 1, "kleiner als 1") # eigentlich sinnvoll: testen ob der Wuerfel wirklich zufaellig ist ... aber sehr aufwendig :-) if __name__ == '__main__': unittest.main(verbosity=0)
Aufruf mit ./test_wuerfel.py
Ist mein Python-Code "schön" in Syntax und Formatierung oder enthält er gar Fehler? Hinweise darauf erhält man von einem Tool wie pylint.
Wenn man vom VIM aus pylint aufruft, kann man sich zu den jeweiligen Stellen leiten lassen.
pylint als "Make Programm" einstellen
ESC:set makeprg=pylint\ --reports=n\ --msg-template=\"{path}:{line}:\ {msg_id}\ {symbol},\ {obj}\ {msg}\"\ %:p
make aufrufen
ESC:make
Fehlerfenster anzeigen lassen
ESC:cw
mit STRGW hüpft man vom Codefenster zum Fehlerfenster und zurück
Mit 2to3 baut man alte Python2 Skripte häufig ganz gut nach Python3 um.
Nachher testen schadet aber nicht … und mit pylint genauer analysieren auch nicht.
Ein paar Überraschungen bleiben einen gelegentlich dennoch nicht erspart.
Beispiel: unter Python3 gibt es Strings in 2 verschiedenen Geschmacksrichtungen: Byte-Strings und Unicode-Strings wo vorher im Python-Skript einfach nur Strings als Ergebnis zurück kamen.
Hier ein Auszug aus einem Python2 IMAP-Script, dass mit Message-Ids arbeitet (hier wird eine Liste der IDs als String mit Kommas zusammengefasst):
message_set = ','.join(msgidliste)
Und hier mit Python3 (die Message-Ids in der Liste waren auf einmal Byte-Strings und müssen vor dem Join erst mal umgewandelt werden):
message_set = ','.join(map(bytes.decode, msgidliste))
Beispiel-Fehlermeldung:
'utf-8' codec can't decode byte 0xb5 in position 10: invalid start byte
Passiert, wenn man binary(Nicht-Text) Dateien so öffnet (was mit Python2.x noch genauso ging):
filehandle = open(local_file, "r")
Bei Python3 muss man dann noch ein b für "binary" dranhängen
filehandle = open(local_file, "rb")
from datetime import date import holidays for Feiertag in holidays.DE(prov = 'BY', years = 2019).items(): print (Feiertag)
ergibt:
(datetime.date(2019, 1, 1), 'Neujahr') (datetime.date(2019, 1, 6), 'Heilige Drei Könige') (datetime.date(2019, 4, 19), 'Karfreitag') (datetime.date(2019, 4, 22), 'Ostermontag') (datetime.date(2019, 5, 1), 'Erster Mai') (datetime.date(2019, 5, 30), 'Christi Himmelfahrt') (datetime.date(2019, 6, 10), 'Pfingstmontag') (datetime.date(2019, 6, 20), 'Fronleichnam') (datetime.date(2019, 8, 15), 'Mariä Himmelfahrt') (datetime.date(2019, 10, 3), 'Tag der Deutschen Einheit') (datetime.date(2019, 11, 1), 'Allerheiligen') (datetime.date(2019, 12, 25), 'Erster Weihnachtstag') (datetime.date(2019, 12, 26), 'Zweiter Weihnachtstag')
siehe: https://www.geeksforgeeks.org/python-holidays-library/
Welcher Wochentag war oder ist an einem bestimmten Datum?
#!/usr/bin/env python3 """Fragt nach Jahr, Monat und Tag und gibt den Wochentag aus.""" import datetime TAGE_DER_WOCHE = ( 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag', ) if __name__ == '__main__': JAHR = input('Bitte Jahr eingeben (Vierstellig):\t') JAHR = int(JAHR) MONAT = input('Bitte Monat eingeben (als Zahl):\t') MONAT = int(MONAT) TAG = input('Bitte Tag eingeben (als Zahl):\t\t') TAG = int(TAG) DATUM = datetime.date(JAHR, MONAT, TAG) WOCHENTAG = TAGE_DER_WOCHE[DATUM.weekday()] HEUTE = datetime.date.today() VERB = "ist" if DATUM < HEUTE: VERB = "war" print(f"\nDer {TAG}.{MONAT}.{JAHR} {VERB} ein {WOCHENTAG}.")
$ ./wochentag.py Bitte Jahr eingeben (Vierstellig): 2019 Bitte Monat eingeben (als Zahl): 3 Bitte Tag eingeben (als Zahl): 18 Der 18.3.2019 war ein Montag.
Zählt 60 Sekunden hohc, stellt den Cursor dabei immer wieder nach vorne und überschreibt so den letzten Eintrag.
Der Trick: Statt Zeilenumbruch einen Carriage Return am Ende ausgeben. Das schreibt sich in Python so: end='\r'
#!/usr/bin/env python3 import time def sekunden(max): for i in range(max): print(f'{i}', end='\r') time.sleep(1) if __name__ == '__main__': zaehler(60)
Motivation: URL-codierten Text nach "lesbar" umwandeln. Das Original-Problem war ein URL-codiertes XML, meine Beispiel-Datei hier ist etwas kürzer …
Beispiel:
$ cat beispiel.txt %3Cp%3EWir%20m%C3%B6gen%20d%C3%A4nisches%20Eis%3Cp%3E
#!/usr/bin/env python3 # url-decode.py3 """url decode an url-encoded file""" import sys import urllib.parse with open(sys.argv[1],'r') as f: read_data = f.read() print((urllib.parse.unquote(read_data)))
Aufruf:
$./url-decode.py3 beispiel.txt <p>Wir mögen dänisches Eis<p>
gilt für alle Tipps, Tricks & Spickzettel:
dies sind einfache, teils banale Notizen für meinen persönlichen Gebrauch,
die hier eher zufällig auch öffentlich lesbar sind
(vielleicht hilft es ja jemandem weiter). Verwendung auf eigene Gefahr
Fehler-Hinweise, Dankesschreiben , etc. bitte an: web.21@unixwitch.de
weitere Tools / Spickzettel