Python

Finde den Fehler:

#!/usr/bin/env python

import sys
if sys.version_info.major < 2 or (sys.version_info.major == 2 and sys.version_info.minor < 7):
    print "python <2.7"
else:
    print "python >=2.7"

Auflösung:
Der Ansatz ist eine nette Idee, funktioniert allerdings erst ab Python 2.7, da Python erst seit dem die benannten Parameter .major und .minor kennt. Damit der Code auch mit Python-Versionen kleiner als 2.7 funktioniert, müsste er wie folgt aussehen:

#!/usr/bin/env python

import sys

if sys.version_info[0] < 2 or (sys.version_info[0] == 2 and sys.version_info[1] < 7):
    print "python <2.7"
else:
    print "python >=2.7"

Siehe auch: http://docs.python.org/library/sys.html#sys.version_info

Das sind Kleinigkeiten, auf die man stößt, wenn man versucht ein auf einem System mit Python 2.7 geschriebenes Skript mit Python 2.6 auszuführen. Wäre ja aber langweilig, wenn alles auf Anhieb glatt laufen würde.

Im Jahr 2007 war ich PHP und all die damit verbundenen Nachteile satt und stieß auf der Suche nach einer Alternative zur Webentwicklung auf Python und das damals noch recht junge Webframework Django. Es war Liebe auf den ersten Blick. Während ich mich in Django einarbeitete und die ersten kleinen “Apps” schrieb, hatte ich regelmäßig aha-Effekte, wenn ich sah, wie einfach sich verschiedene Funktionalitäten implementieren ließen und das wievielfache an PHP-Code man für die gleiche Funktionalität gebraucht hätte.
Doch nicht nur für Webentwicklung lässt sich Django wunderbar nutzen. Wie ich damals recht schnell feststellte, lassen sich aufgrund der Modularität von Django, einzelne Komponenten wunderbar eigenständig nutzen.
Zwei Möglichkeiten möchte ich im Folgenden kurz vorstellen.

Für ein Projekt brauchte ich die Möglichkeit statische Webseiten aus einem via Cron laufenden Skriptes zu generieren. Was bot sich also mehr an, als die Templateengine von Django zu verwenden?
Für ein simples Beispiel reichen sogar schon acht Zeilen Code:

#!/bin/env python

from django.conf import settings
from django.template.loader import render_to_string

settings.configure(TEMPLATE_DIRS=('/home/john/project/templates',))
rendered = render_to_string('template.html', { 'foo': 'cookie' })
print rendered

Das dazugehörige Template könnte wie folgt aussehen:

This is a simple template with {{ foo }}.

Das Ganze lässt sich natürlich nicht nur für HTML-Dateien, sondern für jede Art von Textdateien verwenden.
Ein anderes Anwendungsbeispiel ist die Nutzung des Object-Relational Mappers (ORM) von Django, für hübschen Datenbankzugriff aus beliebigen Python-Anwendungen:

#!/bin/env python

from django.conf import settings

settings.configure(DATABASES={
                    'default': {
                        'ENGINE': 'django.db.backends.sqlite3',
                        'NAME': 'database.sqlite'
                    }
})

from django.db import models

class Animal(models.Model):
    species = models.CharField(max_length=32)
    name = models.CharField(max_length=32)
    
    class Meta:
        app_label = 'animals'

Animal(species='dog', name='rex').save()

for i in Entry.objects.all():
    print i.name

Zu obigem Beispiel seien ein paar Punkte angemerkt:

  • Dass der Import der Models nach dem Konfigurieren der Einstellungen kommt ist Absicht. Django benötigt die Einstellungen zum Laden der Models.
  • Die Meta-Klasse mit der Option app_label muss explizit angegeben werden, sofern man den ORM ohne den Rest von Django nutzt.
  • Das obige Beispiel wird so nicht funktionieren, weil keine Datenbank mit entsprechenden Tabellen existiert. Diese müsste man (in diesem Beispiel) auf anderem Wege anlegen.

Wie man sieht, ist Django toll. Und das nicht nur für Webanwendungen, sondern für alles Mögliche, was auf Python basiert. Wollte ich nur mal gesagt haben.

Im Rahmen meines Hiwi-Jobs beschäftige ich mich zur Zeit mit der Quake3-Engine in Form von ioquake3. Und zwar geht es darum Möglichkeiten auszuloten und gegebenenfalls umzusetzen wie man die Engine am besten auf die VR-Anlage unseres Institutes bekommt um damit beispielsweise virtuelle Rundgänge durch Gebäude zu zeigen.
Dabei stieß ich auf auf einige lustige Sachen. Zum Beispiel fand sich an einer Stelle im Quelltext folgender Kommentar:

// all drawing is done to a 640*480 virtual screen size
// and will be automatically scaled to the real resolution

Ich weiß ja nicht ob alle Spiele das so machen, aber ein bisschen merkwürdig find ich das schon. 😉
Heute beschäftigte ich mich dann ein wenig mit der Kommunikation zwischen Client und Server, da ich dazwischen gegebenenfalls einen Proxy bauen will. Die Kommunikation läuft über UDP. Soweit so gut. Sie läuft aber auch Out-of-Band. Warum habe ich bisher noch nicht rausfinden können, aber in meinen Augen erscheint das leicht sinnlos zu sein. Aber nun gut. Ich wollte mir also in Python einen kleinen UDP-Client schreiben mit dem ich einen Server vorgaukeln kann ich wäre ein Client. Dazu brauchte ich ja aber nun Out-of-Band-Nachrichten. Aber kein Problem: Die Socketbibliothek von Python unterstützt bei allen Sende- und Empfangsfunktionen Flags von recv, unter denen sich auch eins namens MSG_OOB für Out-of-Band-Kommunikation befindet. Für socket.recv funktioniert das Flag, für socket.sendto wo ich es eigentliche brauchte, nicht. Dort kriege ich nur ein schönes

socket.error: (95, ‘Operation not supported’)

Andere Flags funktionieren allerdings.
Falls also einer der Leser dieses Beitrages zufällig weiß, wie man das eventuell doch zum laufen kriegen könnte, dann bin ich froh über jeden Tipp. Ansonsten werd ich das demnächst wohl nochmal in C implementieren müssen. 🙁

Edit: Offensichtlich ist Out-of-Band nur für TCP spezifiziert. Das was bei der Quake-Engine als Out-of-Band bezeichnet wird hat also technisch nichts mit dem eigentlichen Out-of-Band zu tun. Die Pakete sind durchaus in-Band, enthalten aber zu Beginn die Zeichenfolge “0xff 0xff 0xff 0xff” was sie in Quake-Logik zu Out-of-Band-Paketen macht.