for Schleife: enumerate oder nicht?

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.
Antworten
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

Hallo!

Zur Zeit versuche ich (wieder mal) den Einstieg in die Objektorientierung und das parsen eines .html-Dokuments.
Ich habe ein Objekt vom der Klasse lxml.html.Element, welches verschiedene Text-Knoten enthält. Ich will nun wissen: ist der Text jeweils der selbe, oder nicht?
Ein erster Versuch mit set() scheiterte, da die Objekte ja alle unterschiedlich sind...
Mein derzeitiger Ansatz (der auch funktioniert):

Code: Alles auswählen

for i in range(len(Element)-1):
    if str((Element[i]).text_content()) == str((Element[i+1]).text_content()):
        TextIsSingle = True
    else:
        TextIsSingle = False
        break
Angeregt durch einen Thread weiter unten hab ich nun versucht eine Lösung mit enumerate() zu finden, bis jetzt erfolglos...

Was meint ihr? Gibt es noch eine andere, bessere Möglichkeit?

Viele Grüße,
Werner
deets

Mir ist nicht so 100%ig klar, ob du wirklich willst, was du programmiert hast - also immer nur zwei aufeinanderfolgende Elemente vergleichen. Mit allen saehe es so aus:

Code: Alles auswählen

textst = set()
TextIsSingle = True
for e in Element: # schlecht benannt, PEP 8 - besser elements
   text = e.text_content() # das str() drumrum ist wohl cargo-cult-programming
   if text in texts:
         TextIsSingle = False
         break
    texts.add(text)
Wenn deine Aufgabe tatsaechlich so gedacht ist, dann hilft ein dict und enumerate:

Code: Alles auswählen

textst = {}
TextIsSingle = True
for i, e in enumerate(Element): # schlecht benannt, PEP 8 - besser elements
   text = e.text_content() # das str() drumrum ist wohl cargo-cult-programming
   if text in texts:
         if texts[text] + 1 == i:
              TextIsSingle = False
              break
   texts[text] = i
deets

Und noch ein Nachtrag: mit OO hat das ganze natuerlich nur sehr beschraenkt zu tun - Datenstrukturen viel eher, und die muss man natuerlich auch beherrschen. ElementTree ist natuerlich OO, aber das ist in Python ja auch so ziemlich alles andere.
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

Hallo deets,

danke für die Vorschläge.

Es wäre sicher konsequenter jeden einzelnen Text mit jedem anderen zu vergleichen, für mich reicht schon "1 Element weicht ab" für TextIsSingle = False. Da müsste doch mein Vergleich ausreichend sein, oder fällt euch ein Szenario ein bei dem's nicht funktioniert?

Verstehe: der Ansatz ist nicht "Mach aus dem Objekt ein Set und schau nach..." sondern "iterier über das Objekt, pack die texte in ein Set und schau dann nach". Schlau aber auch ;-)

PS: textst (jeweils 1. Zeile) ist ein Schreibfehler und soll texts heissen?
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

Von mir auch noch ein Nachtrag zum Code mit dem set():

müsste nicht beim 2. Durchgang die Bedingung "if text in texts:" dann erfüllt sein, wenn die beiden verglichenen Texte identisch wären? Denn im 1. Durchgang wurde ja in dem Fall genau der text hinzugefügt. Dann wäre "TextIsSingle = False" was aber meiner Voraussetzung ""1 Element weicht ab" für TextIsSingle = False widerspräche???

Ich hoffe Du verstehst was ich meine?
deets

nicht wirklich. kann sein, dass ich True/False vertauscht habe, den TextIsSingle ist fuer mich falsch, wenn derselbe Text mehrfach vorkommt - wenn ich mir jetzt nochmal deinen code anschaue, dann machst du das genau umgedreht.

Das ist aber am Ende ja auch wurscht. Vielleicht beschreibst du erstmal, *was* du wirklich erreichen willst.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Müsste nicht dies hier reichen?

Code: Alles auswählen

def is_single_text(elements):
    return len(set(e.text_content() for e in elements)) > 1
Ich nehme alle Texte, stecke sie in ein Set und wenn es mehr als ein Element enthält, sind die Texte unterschiedlich.

Stefan
deets

@sma

*facepalm* alles klar, ich hab gar nicht richtig gerafft, was er da macht. Klar, so ist das natuerlich richtig.
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

@Stefan: der Ansatz mit set() war auch meine 1. Idee, nur bis zur List-Comprehension bin ich nicht gekommen, Danke dafür!

@ deets: Die Verwirrung um TextIsSingle würde ich gerne noch auflösen, wie hättest Du die Variable in meinem Fall genannt? Zu deinem Fall würde mir "TextIsUnique" einfallen. (Mir geht's hier nicht um richtig oder falsch sondern darum andere Perspektiven zu sehen)

Was ich erreichen will:
Die Textknoten enthalten verschiedene Autoren, die ich deren Texten zuordnen will (welche woanders auf der .html-Seite stehen)
Falls alle Texte dieser Seite vom selben Author stammen, speicher ich jeden Text als "Titel" im Ordner "Author"
Falls die Texte dieser Seite verschiedene Autoren haben kommen die Texte in der Form "Author - Titel" in den Ordner "Verschiedene"

Ich brauch die Variable also später im Code zur Unterscheidung...
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ab Python 2.7 gehen übrigens auch die neuen Zeichenliterale für das Set:

Code: Alles auswählen

len({e.text_content() for e in elements}) > 1
deets

@mcdwerner

Unique ist besser als single, aber wenn du einen solchen Anwendungsfall hast, dann wuerde ich das Ding auch gleich same_author nennen, und das in eine Funktion aehnlichen Namens packen.
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

Bis jetzt hab ich mich gescheut solche "Kleinigkeiten" in Funktionen auszulagern, da ich hier im Forum mal gelesen habe, dass Funktionsaufrufe in Python recht teuer sind (auch hier geht's mir eher um Grundsätzliches als darum ein paar Nanosekunden Performance aus meinem Programm rauszuholen). Wie handhabt ihr das?
Die Auslagerung in eine Funktion würde sich noch zusätzlich rentieren, wenn ich evtl. außer "gleicher Autor" auch "gleiche Edition" und versch. andere Dinge prüfen wollte...

Ich denke deets hat recht und es würde nicht schaden, wenn ich mich noch mehr mit Datenstrukturenn beschäftigen würde. Habt ihr dazu noch Lesetips? Im Tutorial wird ja nur pythonspezifisch darauf eingegangen, mich würde zusätzlich auch ein allgemeinerer Ansatz interessieren.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Lager deinen Code ruhig in Funktionen aus. Wenn es dir nur um Performance geht, bist du bei Python eh falsch. Meistens kommen aber auch nur ein paar Millisekunden an Vorteil heraus, wofür man mit schlecht lesbarem und damit auch schlecht wartbarem Code bezahlen muss. Würd ich mir gut überlegen.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

mcdwerner hat geschrieben:Bis jetzt hab ich mich gescheut solche "Kleinigkeiten" in Funktionen auszulagern, da ich hier im Forum mal gelesen habe, dass Funktionsaufrufe in Python recht teuer sind [...]. Wie handhabt ihr das?
Ich programmieres es so, dass es für mich möglichst klar und übersichtlich aussieht, was typischerweise viel kleine Funktionen beinhaltet. Dazu schreibe ich Tests und verwende coverage.py. Falls es mir danach zu langsam erscheint, benutze ich cProfile. Danach suche ich für die Flaschenhälse bessere Algorithmen bzw. Datenstrukturen. Wenn ich es umgebaut habe, lasse ich die Tests laufen und fixe danach alle Bugs, die ich inzwischen eingebaut habe. Wenn ich mit der Geschwindigkeit zufrieden bin, bin ich fertig, wenn nicht, fange ich wieder mit cProfile an und wiederhole den Prozess solange, bis ich zufrieden bin, oder merke, dass ein ganz anderer Ansatz her muss. Dann suche ich einen solchen Ansatz und fange ganz von vorne an. Genügend Entwicklungszeit vorausgesetzt, natürlich.

Ansonsten muss man halt mit einem langsamen Programm leben, das aber oft so langsam gar nicht ist, weil "langsam" für den Benutzer oft etwas ganz anderes bedeutet, als für den Programmierer. Schnell für den Benutzer ist zB., wenn das Programm sofort startet und einen nicht minutenlang mit einem Splash Screen belästigt. Oder wenn es schnell auf Benutzereingaben reagiert. Wenn dann einzelne Funktionen länger dauern, hat der Benutzer den Eindruck, dass hier eine komplexe Berechnung in einem schnellen Programm stattfindet, die eben ihre Zeit benötigt. Im umgekehrten Fall, dass das Programm den Eindruck von Zähigkeit hinterlässt, aber ein paar hochoptimierte Funktionen besitzt, wird der Benutzer das gesamte Programm als langsam empfinden. Die Lehre daraus ist, dass man beim Optimieren auf das achten sollte, auf das auch der Benutzer achtet. Man sollte zwar so wie oben beschrieben optimieren, aber das alleine genügt nicht. Man muss den Benutzern über die Schulter schauen.

Gruß,
Mick.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Wenn das Programm 1 Sekunde langsamer läuft, nehme ich das herzlich gerne in Kauf dafür, dass ich den Code extrem übersichtlich, leicht zu warten und dadurch auch sehr leicht zu erweitern habe. Also theoretisch. :mrgreen:
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Kebap hat geschrieben:Wenn das Programm 1 Sekunde langsamer läuft, nehme ich das herzlich gerne in Kauf dafür, dass ich den Code extrem übersichtlich, leicht zu warten und dadurch auch sehr leicht zu erweitern habe. Also theoretisch. :mrgreen:
Bei 1 Sekunde würd ich eigentlich schon so langsam über Verbesserungsmöglichkeiten nachdenken. Aber meistens liegt der Perfomancegewinn ja eher im Millisekundenbereich. 2-3 Methodenaufrufe mehr oder weniger machen den Kohl jedenfalls nicht fett.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Bei 1 Sekunde würd ich eigentlich schon so langsam über Verbesserungsmöglichkeiten nachdenken
Das kommt auf den Anwendungszweck an. Wenn es sich um ein Skript handelt, das gelegentlich läuft, besteht sicher kein Optimierungsbedarf. (Es kann allerdings Spaß machen hier zu optimieren, um zu lernen was wirkt).
Wird der Code aber von anderswo sehr oft aufgerufen, sieht das schnell ganz anders aus.
Antworten