Kleine Python Tricks
Ein paar Python Tipps zum schnellen Nachschlagen. Vor allem die kleinen Hilfsprogramme haben oft den größten Nutzen :)Counter formatieren
Auf der rechten Seite ist gezeigt, wie man einen Counter in Python mit 5 führenden Stellen formatiert. Das ist sehr praktisch, wenn man z.B. viele Dateien numerieren möchte.
import os from glob import glob counter = 0 for file in glob('*.png'): counter += 1 os.rename(file, '%.5d___' % counter + file)
Dateien rekursiv kopieren
Mit diesem Programm werden alle jpg-Dateien, die im Verzeichnis /home/name/fotos/ gespeichert sind oder in dessen Unterverzeichnissen liegen in das aktuelle Verzeichnis kopiert.
import os, shutil for root, dirs, files in os.walk('/home/name/fotos/'): for file in [f for f in files if f.endswith(".jpg")]: print root + file shutil.copy(root + '/' + file, '.')
Thumbnails erstellen
Das folgende Codestück ist gedacht, um aus beliebig großen Bild-Dateien kleinere Thumbnails zu erstellen. Wird der Code ausgeführt, so ist die längste Seite des Thumbnails maximal 640 Pixel lang. Mit Hilfe der Exif-Informationen wird der Thumbnail nach Bedarf gedreht.
import glob from PIL import Image for file in glob.glob('*.jpg'): print file name = file.split('.jpg') img = Image.open(file) try: orientation = img._getexif()[274] if orientation == 3: img = img.rotate(180) elif orientation == 6: img = img.rotate(-90) elif orientation == 8: img = img.rotate(90) except: pass img.thumbnail((640, 640), Image.ANTIALIAS) img.save("z" + file, "JPEG", quality = 100)
URL-Encodieren - Was ist URL-Encoding?
Unter urlencoding versteht man das Transformieren von nicht-druckbaren Zeichen in eine für Browser lesbare Codierung. Zu den nicht-druckbare Zeichen gehören:
- ASCII Kontroll-Zeichen: Die ersten 32 ASCII-Zeichen sowie das Zeichen 127 (von 0x00 bis 0x1F bzw. 0x7F) sind für Steuerzeichen (control character) reserviert. Oft werden diese in Editoren nicht angezeigt und sind daher unsichtbar.
- Nicht ASCII Kontroll-Zeichen: Hierzu gehören Zeichen, die sich nicht im Standard ASCII Zeichensatz, sondern z.B. im ISO-Latin Zeichensatz befinden (Umlaute u.ä.).
- Reservierte Zeichen: Zu den reservierten Zeichen zählen z.B. das Dollar-Zeiczen, das Ampersand-Zeichen, das Plus-Zeichen, das Komma, der Slash, das "at"-Symbol, der Punkt, der Strichpunkt, das Gleichheitszeichen sowie das Fragezeichen. Alle diese Zeichen können innerhalb einer URL eine besondere Bedeutung haben und müssen encodiert werden.
Warum URL's encodiert werden sollten
Werden in einer URL nicht-druckbare oder reservierte Zeichen verwendet, kann dies zu unerwarteten Ergebnissen führen. So werden Kontrollzeichen oft ignoriert oder es kann passieren, dass ein Browser Steuerzeichen falsch interpretiert oder die URL gar nicht anzeigen kann.
Auf der sicheren Seite bleibt man, wenn man für eine URL nur alphanumerische Zeichen, den Trennstrich sowie den Underscore verwendet.
Wann URL's encodiert werden sollten
Überall, wo URL's auftreten, sollten diese auch kodiert werden. Schon das Leerzeichen sollte in der Regel kodiert werden. Aber Achtung: Die http:// Phrase muss niemals encodiert werden, da sie ein Teil der Syntax einer URL ist.
Wie man Zeichen encodiert
In Python geschieht durch die URL-Lib.
Im Code schaut das dann so aus:
import urllib myurl = 'Ich suche (immer) auf Güügle.com' url = 'http://' + urllib.quote('myurl')
Verschlüsselung
Mit dem Modul PyCrypto stellt Python ein Modul zur Verfügung, das in Sachen Verschlüsselung kaum Wünsche offen lässt. Die Implementierung in C ist super schnell und das Modul stellt viele populäre Verschlüsselungsalgorithmen zur Verfügung.
Das folgende kurze Code-Snippet zeigt, wie man mit PyCrypto eine einfache symmetrische Ver- und Entschlüsselung implementieren kann.
Für das vorgestellte Verfahren wird ein geheimer Schlüssel benötigt, der 32 Bytes lang ist. Um dies zu erreichen, wird der SHA-256 digest Algorithmus aus der hashlib Bibliothek verwendet. Er erzeugt aus dem geheimen Schlüssel einen 32-Byte langen Schlüssel. Obwohl dieser Schlüssel dann 32-Byte lang ist, zählt bzgl. der Sicherheit nur die Länge des geheimen Originalschlüssels!
Weiter wird für das Verschlüsseln der CBC-Modus gewählt, der in den meisten Fällen genügt, solange keine speziellen Anforderungen benötigt werden.
Um wirklich sicher zu sein, benötigt das CBC Verfahren jedoch einen Initialisierungsvektor. Hierzu muss der IV für jede Verschlüsselung erneut zufällig erzeugt werden. Der IV selbst kann dabei einem Angreifer bekannt sein - wichtig ist nur das erneute Erzeugen des IV.
Da der Algorithmus binäre Strings erzeugt, die sich schlecht zum Versenden in E-Mails, als Teil einer URL oder für einen HTTP Post Request eignen, werden diese mit Hilfe des Moduls base64 in Text Strings umgewandelt. Mehr Informationen dazu liefert der Artikel Python und Unicode.
Zum Schluss sei noch angemerkt, dass dieser Low-Level Algorithmus nur 16-Byte-Blocks als Eingabe akzeptiert. Deshalb wird im folgenden Beispiel der Eingabewert auf 16-Byte erweitert.
Weitere Informationen - vor allem wie man auch komplette Dateien Verschlüsseln kann - finden sich in dem Artikel AES encryption of files in Python with PyCrypto von Eli Bendersky.
from Crypto.Cipher import AES import base64, hashlib, random, urllib secret_key = 'abcdefgh' key = hashlib.sha256(secret_key).digest() iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16)) mode = AES.MODE_CBC encryptor = AES.new(key, mode, iv) value = 1234 ciphertext = encryptor.encrypt('%.16d' % value) print ciphertext decryptor = AES.new(key, mode, iv) print int(decryptor.decrypt(ciphertext)) # ------------------------------ # text strings for transfer # ------------------------------ key_transfer = base64.b64encode(key) iv_transfer = base64.b64encode(iv) print key_transfer print iv_transfer decryptor = AES.new(base64.b64decode(key_transfer), mode, base64.b64decode(iv_transfer)) print int(decryptor.decrypt(ciphertext)) # ----------------------------- # url secure text strings # ----------------------------- key_transfer = base64.urlsafe_b64encode(key) iv_transfer = base64.urlsafe_b64encode(iv) print key_transfer print iv_transfer decryptor = AES.new(base64.urlsafe_b64decode(key_transfer.encode('utf-8')), mode, base64.urlsafe_b64decode(iv_transfer.encode('utf-8'))) print int(decryptor.decrypt(ciphertext))
Verzeichnisse rekursiv durchlaufen und Dateien umbenennen
Mit dem folgenden kleinen Programm werden alle Dateien eines Verzeichnisses angezeigt und umbenannt, indem dem Dateinamen ein formatierter Counter hinzugefügt wird.
import os, shutil counter = 0 for file in os.listdir('./'): counter += 1 print file os.rename(file, './%.5d___' % counter + file)
Zeit und Datumsfunktionen
Dieser Abschnitt gibt einen Überblick über die verschiedenen Funktionen des Time-Moduls. Hier eine kleine Auswahl:
- Zählen und Anzeigen von Sekunden und Millisekunden
- Zeitmessung einer Schleife
- Den Tag einer Woche herausfinden
In dem Fall hat der Codeauszug die 20 Zeilen ein wenig überschritten :) Wird aber - wenn mal etwas Zeit übrig ist - in kleinere und leichter verständliche Codefragmente aufgeteilt.
import time print "Funktionen des Time Moduls:" for fnc in dir(time): print fnc print time.time(), " Sekunden seit 1. Januar 1970 00:00:00" print time.time()/(60*60*24), "Tage seit 1. Januar 1970" # time.clock() gibt die aktuelle Prozessorzeit zurück. # Was dies konkret bedeutet, hängt von der gleichnamigen # C-Funktion ab, die zu diesem Zweck aufgerufen wird. # Unter Unix gibt time.clock die Prozessorzeit zurück, die der Python-Prozess schon benutzt hat. # Unter Windows ist es der zeitliche Abstand zum ersten Aufruf der Funktion. # time.time() ist portabler und gibt den aktuellen Unix-Zeitstempel in UTC als Gleitkommazahl zurück. print "Verwendung von time.clock(): ", time.clock() print "\nZeitmessung von 1 Million 'for' Schleifen..." start = time.clock() for x in range(1000000): y = x end = time.clock() print "Benötigte Zeit in Sekunden: ", end - start # Erzeugen von Datumsangaben timeHere = time.localtime() print "\nDatumsangaben unter Verwendung von time.localtime():" print "(Jahr, Monat, Tag, Stunde, Minute, Sekunde, Wochentag (Montag=0), Jahrestag, dls-flag)" print timeHere # Besser Lesbare Datumsangabe # z.B. Sat Mar 05 22:51:55 2005 print "\nVerwenden von time.asctime(time.localtime()):", time.asctime(time.localtime()) # Die gleichen Ergebnisse print "\nVerwendung von time.ctime(time.time()):", time.ctime(time.time()) print "\nVerwendung von time.ctime():", time.ctime() print "\nVerwendung von strftime():" print "Tag und Datum:", time.strftime("%a %m/%d/%y", time.localtime()) print "Tag, Datum :", time.strftime("%A, %B %d, %Y", time.localtime()) print "Zeit (12 Stunden) :", time.strftime("%I:%M:%S %p", time.localtime()) print "Zeit (24 Stunden) :", time.strftime("%H:%M:%S", time.localtime()) print "TagMonatJahr:",time.strftime("%d%b%Y", time.localtime()) print print "Zum Sortieren:",\ time.strftime("%Y/%m/%d %H:%M:%S", time.localtime()) print def getDayOfWeek(dateString): # Wochentag (Montag = 0) t1 = time.strptime(dateString,"%m/%d/%Y") t2 = time.mktime(t1) return(time.localtime(t2)[6]) Weekday = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] # Beginn der Unixzeitrechnung print "Der 12. November 1970 war ein", Weekday[getDayOfWeek("11/12/1970")] print print "Zeitdifferenzen (12 Stunden Format) eines Tages:" time1 = raw_input("Zeit eingeben (format 11:25:00AM or 03:15:30PM): ") timeString1 = "03/06/05 " + time1 timeTuple1 = time.strptime(timeString1, "%m/%d/%y %I:%M:%S%p") time2 = raw_input("Zeit eingeben (format 11:25:00AM or 03:15:30PM): ") timeString2 = "03/06/05 " + time2 timeTuple2 = time.strptime(timeString2, "%m/%d/%y %I:%M:%S%p") # Sekunden seit 1. Jan. 1970 00:00:00 time_difference = time.mktime(timeTuple2) - time.mktime(timeTuple1) print "Zeitdifferenz = %d Sekunden" % int(time_difference) print "Zeitdifferenz = %0.1f Minuten" % (time_difference/60.0) print "Zeitdifferenz = %0.2f Stunden" % (time_difference/(60.0*60)) print print "Warten" time.sleep(1.5)
Zufallszahlen erzeugen
Python bietet eine Reihe von Möglichkeiten an, um Zufallszahlen schnell und einfach zu erzeugen. Weitere Infos dazu gibt's bei Galileocomputing.
import random random.randint(1, 10) # Erzeugt Zufallszahlen im Bereich 1 bis 10 random.choice([1,2,3,5,7,11]) # Wählt ein zufälliges Element aus l = [1,2,3,4] random.shuffle(l) # Vermischt die Elemente zufällig print l # Ein Ergebnis kann so aussehen: [2, 4, 3, 1] l = [1,2,3,4,5,6,7,8,9,10] random.sample(l, 3) # Wählt 3 zufällige Elemente aus der Liste aus random.random() # Erzeugt eine zufällige Gleitkommazahl n, so dass 0.0
Wer weitere kleine Hilfsprogramme kennt, die immer wieder benötigt werden, aber nicht immer gleich zur Hand sind, kann diese hier gerne vorstellen oder einen entsprechenden Vorschlag machen. Die Programme sollten dabei nicht viel länger als 20 Zeilen und nach Möglichkeit leicht verständlich sein.
Der Artikel wird ständig erweitert und verbessert und stellt mit diesen Progrämmchen ein kleines Nachschlagewerk für alle Python Programmierer dar, die schnell mal was nachschauen möchten.
Bildquelle:
Paul-Georg Meister
(Eigene Homepage erstellen? Das is zu beachten)