Hallo Olaf,
On Sun, 2003-11-23 09:08:12 +0100, Olaf 'Ruebezahl' Radicke wrote:
> Am Sam, 2003-11-22 um 16.35 schrieb Stefan Schwarzer:
> [..]
> > Wenn du "langen verworrenen" Code hast, _schreit_ das nach
> > Vereinfachung/Refaktorierung des Codes, unabhängig davon, ob die
> > Verknüpfung eines Namens mit einem bestimmten Typ möglich ist oder
> > nicht. :-) Letzteres flickt das eigentliche Problem nur sehr
> > notdürftig.
>
> OK. Um mal wieder vom "Allgemeinen" zum "Speziellen" zu kommen:
> Ich habe eine Klasse "Config" die eine XML-Datei parst und die
> Werte den anderen Klassen mit get-Methoden zur Verfügung stellt.
>
> Jetzt habe ich ja meine Socket-Klasse und die braucht einen
> Rechnernamen und ein Port. Der Rechnername ist ein str und
> der Port ein unsigned int. Wo auf dem Weg von der XML-Datei
> zur Socket-Instanz soll ich den str in ein int umwandeln, so
> das später noch klar ist ab wo ich es mit was zu tun habe.
ich würde mir überlegen, was der "natürlichste" Typ (also der, der die
abstrakte Sicht am besten wiedergibt) für eine Größe ist, und diesen
so früh wie möglich (direkt beim Parsen der XML-Datei) einstellen und
dabei bleiben.
Manchmal lässt sich die Frage nach dem "natürlichsten" Typ nicht so
leicht beantworten, aber in den meisten Fällen wird eine Größe nur mit
zwei Typen verwendet:
- Ausgabe
- alles andere
Dann würde ich den für "alles andere" als "natürlichen" Typ ansehen,
und für die Ausgabe etwas wie
warning = "Port %d is a superuser port" % port # `port` is an int
verwenden.
Wenn dir das nicht reicht, wäre eine andere - aber deutlich
aufwändigere! - Möglichkeit, eine Klasse `Port` zu definieren:
class Port:
def __init__(self, port):
self._port = int(port)
def as_string(self):
return str(self._port)
def as_int(self):
return self._port
Du solltest dann eine Instanz der Klasse so früh wie möglich erzeugen,
also wieder beim Parsen der Konfiguration.
> Wenn mir jetzt später ein fällt, ich will wissen ob eine
> privilegierte Port-Nummer benutzt wird, muss ich den ganzen
> Code durchgehen, wo immer der Wert mal durch gereicht wurde,
> um sicher zu stellen, das diese Code auch das tut was ich
> von ihm erwarte:
Generell solltest du die Möglichkeit, dass es mal das eine oder das
andere sein kann, vermeiden, indem du den Typ so früh wie möglich und
konsistent festlegst.
Wenn du den String oft brauchen solltest, kannst du die Häufigkeit von
Missverständnissen verringern, indem du den Typ explizit im Namen
unterbringst:
port_string = str(port)
(Wenn du so einen Namen verwendest und der zugewiesene Wert
tatsächlich ein int ist, hast du zugegebenermaßen ein Problem. ;-) )
> SUPERUSERPORTS = 1024
>
> if conf.get_port_numder() <= SUPERUSERPORTS:
> print "bist du wahnsinnig? Du benutzt Port:", conf.get_port_numder()
>
> > Du kannst in Python nicht "aus einem int ein str" machen. Ein Objekt
> > hat immer einen bestimmten Typ (außer vielleicht so pathologischen
> > Fällen wie Zuweisungen an __class__ ;-) ). Meinst du eher "eine
> > Funktion/Methode akzeptiert ein int und gibt ein str zurück"?
>
> Ich will nicht ein und der selben Instanz mal dies, mal das
> zuweisen dürfen und schon gar nicht Äpfel mit Birnen vergleichen.
Dann tu es einfach nicht ;-))
> > C oder C++ zu verwenden hat m. E. nichts mit der Größe des Projekts zu
> > tun, sondern mit der Art des Projekts. Ich kann mir gut vorstellen,
> > dass auch für viele "große" Projekte Python weitaus besser als C/C++
> > geeignet ist/wäre.
>
> Ich werde in meinem Code XML in LaTeX parsen. Das ging
> in C++ rasant schnell. Ich werde sehen was Python dabei
> für eine Figur macht. Was Größe angeht, hat Zope und Mailman
> usw. gezeigt was geht.
Empfehlung:
1. alles in Python programmieren; dabei _nicht_ "vorsorglich"
optimieren
2. möglichst realistische Anwendungsfälle testen
3. wenn es _wirklich_ zu langsam ist, mit dem Profiler (Modul profile)
messen, wo die tatsächlichen Geschwindigkeitsprobleme sind; man
kann mit einer Schätzung "aus dem Bauch" manchmal (oder sogar oft)
enorm danebenliegen, wodurch man an völlig falschen Stellen
"optimieren" würde
4. überlegen, ob das Problem ganz anders gelöst werden kann, so dass
der geschwindigkeitskritische Teil gar nicht ausgeführt werden
muss; an dieser Stelle fällt einem manchmal ein viel einfacheres
Design ein
5. wenn der Aufwand nicht zu groß ist, den Code so ändern, dass die
geschwindigkeitskritischen Teile auf der C-Ebene von Python
ablaufen (z. B. Verwendung von Listen, Dictionaries, re-Modul etc.)
6. wenn 4. oder 5. zu aufwändig wären oder nicht funktionieren, nach
frei verfügbaren Modulen suchen, die geschwindigkeitsoptimiert sind
und im wesentlichen das machen, was du willst (z. B. SAX, PyXML,
mx.TextTools, NumericPython etc.)
7. wenn 6. nicht geht, aus dem geschwindigkeitskritischen Teil eine
C-Erweiterung machen oder Hilfsmittel wie bspw. psyco
(http://psyco.sourceforge.net/) verwenden
Je mehr Code in C/C++ vorliegt, desto schwieriger wird es sein, die
Punkte 4, 5 und 6 anzuwenden. Das spricht paradoxerweise für _weniger_
statt mehr C/C++, um längerfristig die beste Geschwindigkeit zu
erreichen bzw. beim "Tunen" flexibel zu bleiben.
Eine Frage an die Leser der Mailingliste: Wie sind eure Erfahrungen
bzw. was sollte in der obigen Liste ergänzt/geändert werden?
Viele Grüße
Stefan