Benutzer-Werkzeuge

Webseiten-Werkzeuge


de:sysadmin:tools:python3

Python3 Spickzettel

There should be one– and preferably only one –obvious way to do it. 1)

7x Formatierter Text (python printf)

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 :-)

Traditionelle String-Formatierung

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})

"Moderne" String-Formatierung

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))

Noch moderner: Python String-Formatierung mit f-String

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)

Unittest - ein ganz kleines Beispiel

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

VIM und pylint

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

2to3

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))

Kleine Python3 Scripts

Feiertage in Bayern

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/

Wochentage

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.

Sekunden-Zähler (eine Minute lang) - Carriage Return

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)

URL-codierten Text "entschlüsseln"

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>

Coole Libraries, noch nicht getestet

  • cutie - Command line User Tools for Input Easification (Checkboxen u.ä. in der Konsole)
2) Diesen Absatz aufgeschrieben habe ich übrigens bei einem kurzem Aufenthalt in den Niederlanden ;-)
de/sysadmin/tools/python3.txt · Zuletzt geändert: 2019-03-27 14:59 von hella

Seiten-Werkzeuge