Grundlage für größeres Programm - was verbessern?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Hallo zusammen,

nachstehender Code soll ein Ausgangsbeispiel für ein "größeres Programm" werden.

Deutsche Namen sind Absicht. Würdet ihr sonst irgendwas anders machen, wenn ja, warum?

Code: Alles auswählen

text = """Österreich ist ein schönes Land.
Grüße an alle aus dem Ländle."""

umlaute_codecs = {"Ö":"Ö","ö":"ö",
                  "Ä":"Ä","ä":"ä",
                  "Ü":"Ü","ü":"ü",
                  "ß":"szlig"}

for zeichen in text:
    if zeichen in umlaute_codecs.keys():
        text = text.replace(zeichen,umlaute_codecs[zeichen])


print text
Vielen Dank im Voraus

rolgal_reloaded
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Sieht nach HTML aus, da würden dann aber noch einige fehlen.
Nur als Beispiel:

Code: Alles auswählen

& für & 
< für <
> für > 
usw... 
Ich denke das es da bestimmt fertige module im html Bereich gibt.
Würde vielleicht da mal ein bisschen forschen.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Hallo zap,

ja klar fehlen da noch einige. Das war jetzt aber nicht wichtig.
Mir ging es um die Vorgangsweise.

Dictionary,
Formulierung der Schleife usw.

Wobei ich nicht meine es in eine Funktion zu packen usw.

LG

rolgal
BlackJack

Das ist sehr fragil weil `text` keine Zeichen sondern Bytes enthält, und das Dictionary auch. Wenn man mit Zeichen arbeiten will, insbesondere ausserhalb von ASCII, sollte man sich mit Unicode auseinandersetzen.

Beim Wert zum 'ß' fehlen '&' und ';'.

Bei der Schleife gibt's eigentlich zu allen drei Zeilen etwas zu sagen.

Erstmal die Schleife: Warum muss man sich jedes Zeichen anschauen? Mal angenommen der `text` ist 'äbbä', dann wird die Schleife 4-mal durchlaufen. Beim ersten mal werden alle 'ä' ersetzt, beim 4. mal auch wieder, obwohl gar keine mehr vorhanden sind.

In der ``if``-Abfrage ist der Aufruf von `keys()` nicht nur überflüssig, ``in`` ist auf Dictionaries schon so definiert, das auf Schlüssel getestet wird, sondern es wird für jedes Zeichen im Text eine Liste mit den Schlüsseln erzeugt, linear(!) durchsucht und dann wieder weggeworfen.

Die letzte Zeile ist vertretbar, wenn die äussere Schleife besser wäre, allerdings wird für jedes `replace()` der gesamte Text durchlaufen. Mit `re.sub()` liesse sich das eventuell mit linearer Laufzeit lösen.

Man sollte es mindestens hierauf beschränken:

Code: Alles auswählen

    for sonderzeichen, entity in umlaute_codecs.iteritems():
        text = text.replace(sonderzeichen, entity)
Der Name `umlaute_codecs` ist nicht ganz passend, da auch ein 'ß' enthalten ist.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

BlackJack hat geschrieben:Das ist sehr fragil weil `text` keine Zeichen sondern Bytes enthält, und das Dictionary auch. Wenn man mit Zeichen arbeiten will, insbesondere ausserhalb von ASCII, sollte man sich mit Unicode auseinandersetzen.

Beim Wert zum 'ß' fehlen '&' und ';'.
Das war ein Versehen.
BlackJack hat geschrieben: Bei der Schleife gibt's eigentlich zu allen drei Zeilen etwas zu sagen.

Erstmal die Schleife: Warum muss man sich jedes Zeichen anschauen? Mal angenommen der `text` ist 'äbbä', dann wird die Schleife 4-mal durchlaufen. Beim ersten mal werden alle 'ä' ersetzt, beim 4. mal auch wieder, obwohl gar keine mehr vorhanden sind.

In der ``if``-Abfrage ist der Aufruf von `keys()` nicht nur überflüssig, ``in`` ist auf Dictionaries schon so definiert, das auf Schlüssel getestet wird, sondern es wird für jedes Zeichen im Text eine Liste mit den Schlüsseln erzeugt, linear(!) durchsucht und dann wieder weggeworfen.
?? Meintest du vielleicht:
``in`` ist auf Dictionaries schon so definiert, dass nicht auf Schlüssel getestet wird, sondern es wird für jedes Zeichen im Text eine Liste mit den ......



Sonst versteh ich es nämlich nicht, also den Satz ansich nicht.

BlackJack hat geschrieben:
Die letzte Zeile ist vertretbar, wenn die äussere Schleife besser wäre, allerdings wird für jedes `replace()` der gesamte Text durchlaufen. Mit `re.sub()` liesse sich das eventuell mit linearer Laufzeit lösen.

Man sollte es mindestens hierauf beschränken:

Code: Alles auswählen

    for sonderzeichen, entity in umlaute_codecs.iteritems():
        text = text.replace(sonderzeichen, entity)
Das ist cool!
BlackJack hat geschrieben: Der Name `umlaute_codecs` ist nicht ganz passend, da auch ein 'ß' enthalten ist.
Ja logo, ich habe zuerst nur mit Umlauten rumgemacht.....dann erst das ß hizugefügt. Sinnvoll natürlich es anders zu benennen.
Danke für den Hinweis.

LG

rolgal
BlackJack

rolgal_reloaded hat geschrieben:
BlackJack hat geschrieben:In der ``if``-Abfrage ist der Aufruf von `keys()` nicht nur überflüssig, ``in`` ist auf Dictionaries schon so definiert, das auf Schlüssel getestet wird, sondern es wird für jedes Zeichen im Text eine Liste mit den Schlüsseln erzeugt, linear(!) durchsucht und dann wieder weggeworfen.
?? Meintest du vielleicht:
``in`` ist auf Dictionaries schon so definiert, dass nicht auf Schlüssel getestet wird, sondern es wird für jedes Zeichen im Text eine Liste mit den ......

Sonst versteh ich es nämlich nicht, also den Satz ansich nicht.
Ich meinte es schon so wie's da steht. Aber den Satz kann sehr leicht falsch verstehen. Ich sollte mir so lange Sätze mit vielen Kommata abgewöhnen. :-)

Was bei Dir passiert: Für jedes Zeichen in `text` wird eine Liste mit den Schlüsseln erzeugt (`keys()`) und auf diese *Liste* wird dann der ``in``-Operator angewandt. Das bedeutet es wird für jedes Zeichen diese Liste erzeugt und linear nach `zeichen` durchsucht.

Der ``in``-Operator auf Dictionaries ist aber schon so definiert, das er das Objekt links vom Operator in den Schlüsseln sucht. Das allerdings ohne eine temporäre Liste zu erzeugen und auch nicht linear sondern in O(1)-Zeit.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Schau Dir mal das Standardmodul 'htmlentitydefs' an. Es enthält bereits fertige Dicts.
MfG
HWK
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Hi BlackJack,

so toll bzw. sinnig das mit iteritems() ist, so schwierig ist es für Anfänger sich was konkretes darunter vorzustellen.

<dictionary-itemiterator object at 0x00C441A0>

Wie soll ich das ausdeutschen??

Vor allem wenn mir selbst damit noch nicht alles klar ist, ggg.




@HWK
Danke für den Tipp! Ich möchte trotzdem mal etwas damit rumspielen.

LG

rolgal_reloaded
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

...nochmal ein Vorschlag, man wenn man nicht dauernd programmiert,...dann ist es mühsam immer das beste parat zu haben.

Mit iteritems() bin ich nicht ganz glücklich. Ist folgende Lösung nicht ebenso vertretbar und wesentlich besser wie mein erster Vorschlag?

Code: Alles auswählen

text = """Österreich ist ein schönes Land.
Grüße an alle aus dem Ländle."""

sonderzeichen_codecs = {"Ö":"Ö","ö":"ö",
                  "Ä":"Ä","ä":"ä",
                  "Ü":"Ü","ü":"ü",
                  "ß":"ß"}

for sonderzeichen, entity in sonderzeichen_codecs.items():
    text = text.replace(sonderzeichen, entity)
Also nur über die Liste die items zurückgibt iterieren, anstatt ein Iterationsobjekt zu erzeugen.

Oder ist das so ein immenser Nachteil?

LG

rolgal_reloaded
BlackJack

Das ist ein Iterator über die Elemente in dem Dictionary, also über (Schlüssel, Wert)-Tupel. Und das kann man doch ganz einfach zeigen und ausprobieren:

Code: Alles auswählen

In [87]: a = umlaute_codecs.iteritems()

In [88]: a
Out[88]: <dictionary-itemiterator object at 0xb772c8e0>

In [89]: a.next()
Out[89]: ('\xc3\xb6', 'ö')

In [90]: a.next()
Out[90]: ('\xc3\xbc', 'ü')

In [91]: a.next()
Out[91]: ('\xc3\xa4', 'ä')
Iteratoren oder "iterables" im allgemeinen ist ein extrem grundlegendes Konzept von Python, schliesslich baut die am meisten genutzte Schleifenform darauf auf.

Ansonsten kannst Du auch sagen, dass ist wie die `items()`-Methode, nur speicherschonender:

Code: Alles auswählen

In [93]: umlaute_codecs.items()
Out[93]:
[('\xc3\xb6', 'ö'),
 ('\xc3\xbc', 'ü'),
 ('\xc3\xa4', 'ä'),
 ('\xc3\x9f', 'szlig'),
 ('\xc3\x9c', 'Ü'),
 ('\xc3\x84', 'Ä'),
 ('\xc3\x96', 'Ö')]
Edit: In Python 3.0 sollen die "normalen" Methoden auf `dict()` verschwinden und durch durch die `iter*()`-Varianten ersetzt werden. Dann verhält sich also `items()` so wie `iteritems()` heute.
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

[offtopic]
Edit: In Python 3.0 sollen die "normalen" Methoden auf `dict()` verschwinden und durch durch die `iter*()`-Varianten ersetzt werden. Dann verhält sich also `items()` so wie `iteritems()` heute.
bleiben aber bestehen, oder? Ich meine... sonst wär ja einiges nicht kompatibel ;)
und btw: gibt es schon nen genauen Zeitplan für 3.0? (sollen ja einige Interessante Sachen kommen, hab ich mal irgentwo gelesen)
[/offtopic]
Mephisto
User
Beiträge: 28
Registriert: Mittwoch 17. Januar 2007, 15:52

Soweit ich weis, hat man bei Python 3k nicht vor unbedingt rückwärtskompatibel zu bleiben, um gewisse Dinge anders zu machen als im Python2.x-Zweig wo man ja auf kompatibilität Wert legt.
Ausserdem wird es Python2.x vermutlich eine ganze weile paralell zu Python 3k geben.
Hoffe das war kein stuss, aber wenn korrigiert mich eh jemand :)

greets meph
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

@BlackJack,

ja das geht mir ein bzw. kann mir vorstellen, dass das allgemein gut verständlich so ist.

Danke nochmal

LG

rolgal
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

EnTeQuAk hat geschrieben:[offtopic]
Edit: In Python 3.0 sollen die "normalen" Methoden auf `dict()` verschwinden und durch durch die `iter*()`-Varianten ersetzt werden. Dann verhält sich also `items()` so wie `iteritems()` heute.
bleiben aber bestehen, oder? Ich meine... sonst wär ja einiges nicht kompatibel ;)
und btw: gibt es schon nen genauen Zeitplan für 3.0? (sollen ja einige Interessante Sachen kommen, hab ich mal irgentwo gelesen)
[/offtopic]
Nein, natürlich bleiben die alten Methoden nicht. Sonst wärs ja sinnlos...

Wenn du in 3k eine Liste von Items brauchst, nimm ``list(x.items())``.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

BlackJack hat geschrieben:
Iteratoren oder "iterables" im allgemeinen ist ein extrem grundlegendes Konzept von Python, schliesslich baut die am meisten genutzte Schleifenform darauf auf.

Ansonsten kannst Du auch sagen, dass ist wie die `items()`-Methode, nur speicherschonender:
Lässt das den Schluss zu, dass man dann eigentlich statt keys() und values() immer iterkeys() und itervalues() verwenden sollte - sofern man über die Schlüssel bzw. Werte iterieren will.

Stimmt weiters diese Aussage: items() erzeugt sofort eine ganze Liste der Schlüssel und Werte eines Dictionaries und iteritems() stellt immer nur ein Schlüssel Wertpaar aus dem Dictionary zur Verfügung, quasi das aktuelle.

LG

rolgal_reloaded
Mephisto
User
Beiträge: 28
Registriert: Mittwoch 17. Januar 2007, 15:52

Ich würde nein sagen, da es noch eine ganze Weile dauern wird bis Python 3000 erscheint. Und eine solch einfache Änderung bewältigt jeder Texteditor der über eine Suchen und Ersetzen Funktion verfügt :)

greets meph
BlackJack

@rolgal_reloaded: Jup, die Aussagen stimmen so.

Wie immer gibt's Ausnahmen: Wenn Du über Schlüssel, Werte oder Paare davon iterierst und die das Dictionary in der Schleife veränderst, dann kann es Probleme geben. Ähnlich wie bei Listen über die man nicht (vorwärts) iterieren sollte wenn man in der Schleife Listenelemente entfernt.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

BlackJack hat geschrieben:@rolgal_reloaded: Jup, die Aussagen stimmen so.

Wie immer gibt's Ausnahmen: Wenn Du über Schlüssel, Werte oder Paare davon iterierst und die das Dictionary in der Schleife veränderst, dann kann es Probleme geben. Ähnlich wie bei Listen über die man nicht (vorwärts) iterieren sollte wenn man in der Schleife Listenelemente entfernt.
Denke das habe ich.

Dann stimmt wohl auch, dass das aktuelle Element nachdem es in der Schleife abgearbeitet wurde, sofort aus dem Speicher gelöscht wird, oder?
Sonst wäre es wohl kein so immenser Performancegewinn :?:

Wenn weiters richtig, dann sind die itermethoden auch sehr interessant, wenn innerhalb einer Endlosschleife (while True) z. B. bei einem Vokabeltrainer diese auf Grund einer bestimmten Bedingung verlassen wird (10 Vokabeln hintereinander richtig - Lektionswechsel - neues Dict laden).
Klar und richtig was ich meine?

LG

rolgal_reloaded
BlackJack

Aus dem Speicher gelöscht wird das Element nicht, es ist ja immer noch im Dictionary. Die Elemente werden ja nur an die Namen in der Schleife gebunden und nicht kopiert.
rolgal_reloaded
User
Beiträge: 312
Registriert: Dienstag 24. Oktober 2006, 19:31

Ich meinte natürlich nicht, dass es aus dem Dictionary gelöscht wird.
Aber aus dem Arbeitsspeicher heisst ja nicht aus dem Dictionary :?: :!:

Oder habe ich da technisch was falsch verstanden?

Also ich meine: das muss ja speichertechnisch irgendwie anders verwaltet werden, wie kann es sonst zu einer Steigerung der Performance kommen?
Denn es geht ja darum, dass nicht die ganze Liste auf einmal erzeugt wird bzw. immer nur das aktuelle Element zur Verfügung steht.

Schwierig das in Worte zu fassen :D


LG

r_r
Antworten