Frage zu einer Ausgabe von dis.dis.

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.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Frage zu einer Ausgabe von dis.dis.

Beitragvon sape » Montag 8. Januar 2007, 21:32

Fortführung zu den letzten Posts: http://www.python-forum.de/topic-8700.h ... hlight=24h

Whenever joining more than two strings, use string interpolation, not addition:

Code: Alles auswählen

s = x + y + z # Bad.
s = '%s%s%s' % (x, y, z) # Good.
s = ''.join([x, y, z]) # Best, but not as general.

This has to do with efficiency; the intermediate string x+y is made (and thus copied) before x+y+z is made, so it's less efficient. People who use string concatenation in a for loop will be swiftly kicked in the head.


So weit gut und auch verständlich :) Bis auf die Sache die ich angesprochen habe außerhalb einer Funktion.

Der Vollständigkeit halber nochmal erwähnt was wir bisher wissen, weil das folgende darauf aufbaut:
Es ist "evil" in einer schleife folgendes zu machen, weil es durch das ständige Kopieren (dest += srclin) Ineffizient ist (Kostet unnötige Zeit):

Code: Alles auswählen

dest = ''
source = ['a', 'b', 'c', 'd']
for srclin in source:
    dest += srclin


Stattdessen sollte man diese Methode nutzen weil dabei das Kopieren entfällt und so Zeit spart. Das verbinden wird einmalig am ende der Schleife gemacht:

Code: Alles auswählen

dest = list()
source = ['a', 'b', 'c', 'd']
for srclin in source:
    dest.append(srclin)
dest = "".join(dest)


Den ``dis.dis`` Output spare ich mir an dieser stelle.

...

Außerhalb wäre 's = ''.join([x, y, z])' langsamer als 's = x + y + z' und würde auch mehr speicher verbrauchen (wirklich mehr speicher verbrauch wegen der angelegten temporären ``list``? {EDIT: Nein, es wird lediglich eine ``list`` angelegt und die Objekte an dem entsprechenden Index referenziert,}). ``dis.dis`` Output ist im anderen Thread der zumindest Zeigt das es schneller geht weil weniger Aufrufe, keine temporäre ``list`` erzeugt werden/wird:

Code: Alles auswählen

...
s = x + y + z # Meiner Meinung Besser.
s = ''.join([x, y, z]) # Speicher(?) und Performance Verschwendung!


Nun zur eigentlichen Frage:
Nun steht oben das ``s = '%s%s%s' % (x, y, z)`` besser ist als ``s = x + y + z``. Hab mal ``dis.dis`` benutzt.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from dis import dis

def x():
    x = 'test1'
    y = 'test2'
    z = 'test3'
    return x + y + z

dis(x)


Code: Alles auswählen

  7           0 LOAD_CONST               1 ('test1')
              3 STORE_FAST               0 (x)

  8           6 LOAD_CONST               2 ('test2')
              9 STORE_FAST               1 (y)

  9          12 LOAD_CONST               3 ('test3')
             15 STORE_FAST               2 (z)

 10          18 LOAD_FAST                0 (x)
             21 LOAD_FAST                1 (y)
             24 BINARY_ADD         
             25 LOAD_FAST                2 (z)
             28 BINARY_ADD         
             29 RETURN_VALUE       



Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from dis import dis

def x():
    x = 'test1'
    y = 'test2'
    z = 'test3'
    return '%s%s%s' % (x, y, z)

dis(x)


Code: Alles auswählen

  7           0 LOAD_CONST               1 ('test1')
              3 STORE_FAST               0 (x)

  8           6 LOAD_CONST               2 ('test2')
              9 STORE_FAST               1 (y)

  9          12 LOAD_CONST               3 ('test3')
             15 STORE_FAST               2 (z)

 10          18 LOAD_CONST               4 ('%s%s%s')
             21 LOAD_FAST                0 (x)
             24 LOAD_FAST                1 (y)
             27 LOAD_FAST                2 (z)
             30 BUILD_TUPLE              3
             33 BINARY_MODULO       
             34 RETURN_VALUE


Jetzt brauche ich mal Hilfe zur Interpretation des zweiten Outputs ab Zeile 10.

Meine Interpretation zum ersten Output ab Zeile 10:
``x, y``(18, 21) werden geladen eine BINARY_ADD ausgeführt (24) dann ``z`` (25) geladen und dann auf ``z`` und dem vorherigen Ergebnis wider ein BINARY_ADD ausgeführt (28 ).

Meine Interpretation zum zweiten Output ab Zeile 10:
Erstmal wird ein Call mehr benötigt (18 ), was ja erstmal nichts sagen muss.

``x, y, z`` werden geladen (21, 24, 27) danach wird ein temporäres ``tuple`` erzeugt mit dem Inhalt von ``x, y, z`` (30) und dann der BINARY_MODULO mit ``tuple`` (30) auf ``'%s%s%s'`` (18 ) angewendet.


Was ist nun schneller?

Vom Gefühl her würde ich sagen das dass zweite schneller ist und Speicherschonender als das erste weil, beim ersten zuviel BINARY_ADD durchgeführt werden müssen (Zeit, Speicher) - (probiert mal a + b+ c+ d+ e+ f+ g+ h+ i) - und beim zweiten nur ein ``tuple`` (dessen Inhalt womöglich nur auf x, y, z referenziert und nicht mehr Speicher verbraucht, im Gegensatz zum ersten wo nach jeder Addition Speicher benötigt wird? {EDIT: Wird nur referenziert.}) erzeugt wird, ansonsten nur ``'%s%s%s'`` und ``x, y, z`` geladen werden müssen und als letztes nur eine einmalige Operation ausgeführt werden muss (BINARY_MODULO) :)

Interpretiere ich das so richtig und habe ich die richtigen Schlüsse daraus gezogen und das zweite ist tatsächlich schneller und Speicherschonender?

lg
sape

EDIT: Einige Fehler beseitigt.
Zuletzt geändert von sape am Dienstag 9. Januar 2007, 13:52, insgesamt 1-mal geändert.
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Beitragvon rayo » Montag 8. Januar 2007, 22:27

Hi

Hast du denn ein Programm bei dem eine Version zu langsam ist?

Es scheint mir so als ob du hier zu früh Optimieren willst. Nimm einfach eine Liste und .append wenn du viele Elemente zusammenhängen willst und wenn du nur so 5 nimmst kannst du gut auch die Addition verwenden.

Den Modulo-Operator würde ich nehmen wenn du konstante Strings mit Variablen füllen willste (z.B. "%s had die Fläche %f")

Sonst kannst du auch einen Benchmark durchführen und die Zeit messen.

Gruss
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Montag 8. Januar 2007, 23:33

Was die Geschwindigkeit angeht: bau dir doch einfach mit dem timeit-Modul einen Benchmark.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Dienstag 9. Januar 2007, 10:53

Am Rande: Modulo ist eine arithmetische Funktion. Was du meinst ist %-Formatierung (vgl. *printf() in C), die nur das selbe Symbol als Operator verwendet.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Beitragvon sape » Dienstag 9. Januar 2007, 12:34

rayo hat geschrieben:[...]
Hast du denn ein Programm bei dem eine Version zu langsam ist?
Möchte das in erster Linie Wissen und mir dann auch die beste Methode angewöhnen. Bin erste letztes Jahr gewechselt von ``retval += srclin`` auf die ``list``-"Methode" + einem ``join`` am ende der Schleife. Wusste vorher nicht das es soviel ausmacht (Und da ist noch soviel sourcecode den ich nicht ausgebessert habe :
Leonidas hat geschrieben:quot;]Was die Geschwindigkeit angeht: bau dir doch einfach mit dem timeit-Modul einen Benchmark.
Schon geschähen. Werde heute abend ein par Benchmarks machen. Bloß für die Speichermessung hätte ich gerne eine direkte Möglichkeit in Python.

Y0Gi hat geschrieben:Am Rande: Modulo ist eine arithmetische Funktion.

...genau wie die Addition. Wird aber auch für alles mögliche in Python genutzt (überladen. BZW: Heist das eigentlich auch wie in C++ Überladung oder ist das eher eine Redefinition?). Man kann am output erkenne das für die "Addition" der Instanzen ``x, y, z`` von ``str`` ein BINARY_ADD benutzt wird. Für das andere ein BINARY_MODULO.

Das es mit der arithmetischen Funktion rein Garnichts zu tun hat, ist mir bewusst.

Code: Alles auswählen

18 LOAD_CONST               4 ('%s%s%s')
             21 LOAD_FAST                0 (x)
             24 LOAD_FAST                1 (y)
             27 LOAD_FAST                2 (z)
             30 BUILD_TUPLE              3
             33 BINARY_MODULO       
             34 RETURN_VALUE



Y0Gi hat geschrieben:Was du meinst ist %-Formatierung (vgl. *printf() in C), die nur das selbe Symbol als Operator verwendet.
Das ist mir durchaus bekannt. Komme ja ursprünglich von C, auch wen das _verdammt_ lange her ist.

...

http://docs.python.org/lib/bytecodes.html
Da kann ich folgendes entnehmen:

Code: Alles auswählen

BINARY_ADD
    Implements TOS = TOS1 + TOS.
[...]
INPLACE_MODULO
    Implements in-place TOS = TOS1 % TOS.


lg

BTW:
LOAD_FAST var_num
Pushes a reference to the local co_varnames[var_num] onto the stack.
Da muss ich meine Post nochmal im vorigen Thread ein wenig korrigieren, in Bezug zum Speicherverbrauch, mit ``join([x, y, z])``.

BTW2: Was verbraucht eigentlich die interne Datenstruktur für die Repräsentation einer (Leeren) ``list``. Gibt es darüber Material irgendwo im netz? Ich gehe ja lediglich von ein par kilos aus? Was ist aber die "genaue" Zahl ohne jetzt den C-Sourcecode auseinander zu nehmen?
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Dienstag 9. Januar 2007, 13:25

sape hat geschrieben:
Y0Gi hat geschrieben:Am Rande: Modulo ist eine arithmetische Funktion.

...genau wie die Addition. Wird aber auch für alles mögliche in Python genutzt (überladen. [...])

Ja, Addition gehört auch zur Arithmetik. Wenn man aber arithmetische Operatoren (inklusive + und %) überlädt, dann ist es im Falle von Strings eben nicht mehr das genannte (sondern Konkatenation und Formatierung), auch wenn es noch die selben Symbole als Operatoren verwendet.

sape hat geschrieben:BZW: Heist das eigentlich auch wie in C++ Überladung oder ist das eher eine Redefinition?)

Letztlich ist eine Überladung ja eine Redifinition einer (geerbten) Methode (in wieweit das bei Funktionen möglich ist, weiß ich gerade nicht) und es wird auch als "operator overloading" bezeichnet.

sape hat geschrieben:
Y0Gi hat geschrieben:Was du meinst ist %-Formatierung (vgl. *printf() in C), die nur das selbe Symbol als Operator verwendet.
Das ist mir durchaus bekannt. Komme ja ursprünglich von C, auch wen das _verdammt_ lange her ist.

Es geht mir nur darum, dass auch die richtigen Begriffe verwendet werden und nicht die falschen, die entsprechend auch noch irreführend sind. Nicht nur deinetwegen, sondern auch wegen allen, die das hier irgendwann einmal lesen.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Beitragvon sape » Dienstag 9. Januar 2007, 13:44

Y0Gi hat geschrieben:[...]
Es geht mir nur darum, dass auch die richtigen Begriffe verwendet werden und nicht die falschen, die entsprechend auch noch irreführend sind. Nicht nur deinetwegen, sondern auch wegen allen, die das hier irgendwann einmal lesen.
Ne ok, dann ändere ich das mal schnell und schreibe stattdessen BINARY_MODULO hin, dann weiß man das ich den opcode meine.

lg

EIDT: Hab das nun geändert und das Add auch durch BINARY_ADD ersetzt.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Dienstag 9. Januar 2007, 14:42

Danke :)


Machst du dir nicht vielleicht etwas viel Gedanken?

Ich persönlich finde die Variante mit '%s%s%s' sehr unschön und würde %-Platzhalter nur verwenden, wenn auch noch "richtige Zeichen" im String enthalten sind.

Hier und da mal einige wenige Strings mit + zu verbinden wird auch noch kein Debakel; wenn es das ganze in Einzelfällen (außerhalb von Schleifen) lesbarer macht (und das macht es im Gegensatz zu den anderen beiden Ansätzen), dann geht das in Ordnung.

Wenn es um mehr als einige Elemente geht, dann wird man aus Platzgründen meist ohnehin schon irgendwo eine Liste haben, und die kann und sollte man dann einfach joinen. Aber selbst die muss schon sehr groß sein, um überhaupt ansatzweise ein gutes Ziel für eine Optimierung abzugeben.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Beitragvon birkenfeld » Dienstag 9. Januar 2007, 18:42

sape hat geschrieben:BTW2: Was verbraucht eigentlich die interne Datenstruktur für die Repräsentation einer (Leeren) ``list``. Gibt es darüber Material irgendwo im netz? Ich gehe ja lediglich von ein par kilos aus? Was ist aber die "genaue" Zahl ohne jetzt den C-Sourcecode auseinander zu nehmen?


Ein paar Kilos? Wovon sprichst du?

Eine Liste ist ein Python-Objekt. Als solches ist sie ein C-Struct. Listen haben neben dem Kopf, der Refcount (4 bytes) und Zeiger aufs Typobjekt (4 bytes) enthält, ein Feld mit der Größe (4 bytes) und für jedes Element einen Zeiger (jeweils 4 bytes). Eine leere Liste verbraucht also 12 bytes, eine mit 10 Elementen 52 bytes. Genausoviel übrigens wie ein entsprechendes Tupel.

Die Elemente sind natürlich eigene Objekte, die jeweils wieder einen Kopf und Inhalt haben!
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Dienstag 9. Januar 2007, 19:22

sape hat geschrieben:Möchte das in erster Linie Wissen und mir dann auch die beste Methode angewöhnen. Bin erste letztes Jahr gewechselt von ``retval += srclin`` auf die ``list``-"Methode" + einem ``join`` am ende der Schleife. Wusste vorher nicht das es soviel ausmacht

Die beste Methode ist in der Regel die die am saubersten ist, nicht unbedingt die die am schnellsten ist. So kann es gut sein, dass das was eleganter aber langsamer ist, in einer Zukünftigen Version von Python wesentlich schneller ist, da es zwischendrin optimiert wurde.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
BlackJack

Beitragvon BlackJack » Dienstag 9. Januar 2007, 19:31

Das mit ``'%s%s%s' % (x, y, z)`` kann manchmal praktisch sein weil es nicht nur konkateniert, sondern die Objekte auch in Zeichenketten umwandelt. Es ist also Äquivalent zu ``str(x) + str(y) + str(z)``.

Ich denke aber auch man kann sich da zu viele Gedanken machen. Bytecodes zählen bringt nicht soviel, weil hinter einem Bytecode etwas ganz simples stehen kann und hinter dem nächsten ein Monsteralgorithmus. Was genau passiert ist abhängig von der Implementierung und kann sich in der nächsten Python-Version wieder ein wenig ändern. Dann dürfte es auch davon abhängen wieviele und wie grosse Zeichenketten zusammengefügt werden sollen.

An diesem Fall problematisch ist nur, das sich der scheinbar offensichtliche Algorithmus mit ``+=`` in einer Schleife als Problem in bestimmten Fällen herausgestellt hat. Deswegen gibt's das ``''.join()``-Idiom. Ansonsten würde ich nicht soviel Zeit investieren und Code schreiben der am verständlichsten ist.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Beitragvon sape » Mittwoch 10. Januar 2007, 08:43

Habs gestern noch getestet. "Kein" unterschied.

Code: Alles auswählen

[Die Laufzeit wird ermittelt]
run:      f1 - return x + y           OK (1.73sec.)
run:      f2 - return '%s%s' % (x, y) OK (1.74sec.)

[Ranking wird erzeugt]
Ranking wurde erzeugt.
-------------------------------------------------------------------------------
Funktion: f2 - return '%s%s' % (x, y) ist am langsamsten; Zeit: 1.738071 sec
Funktion: f1 - return x + y           ist um 0.55% schneller; Zeit: 1.728566 sec
-------------------------------------------------------------------------------

Der test wurde gemacht mit 1000 Objekten die zurückgegeben werden. {EDIT: Jedes Objekt hatte einen String der ca. 3000 Zeichen lang ist ^^}.

Den temporären Speicher der zwischenzeitlich in der Funktion ansteigt konnte ich nicht messen. Ich vermute mal das aber ``f1`` verschwenderischer ist.

...

@Y0Gi, Birekenfeld, Leonidas & BlackJack: Danke :)

BlackJack hat geschrieben:An diesem Fall problematisch ist nur, das sich der scheinbar offensichtliche Algorithmus mit ``+=`` in einer Schleife als Problem in bestimmten Fällen herausgestellt hat. Deswegen gibt's das ``''.join()``-Idiom. Ansonsten würde ich nicht soviel Zeit investieren und Code schreiben der am verständlichsten ist.
Daher dachte ich auch das es vielleicht bei ``'%s%s' % (x, y)`` vs. ``x + y`` auch besser wäre wenn ich die eine statt die andere Variante verwenden.

Naja, hab mal wider versucht an der falschen stelle zu Optimieren. Wie sagte einmal Tony Hoare: "Zu frühe Optimierung ist die Wurzel allen Übels".

Vielleicht sollte ich mich daran mehr halten, als immer wider versuchen immer meine Code so oft umzuschreiben damit ich denke das es die schnellste Variante ist. :roll: -> Vor lauter Editierung wird im Grunde nichts fertig...

lg
sape
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Mittwoch 10. Januar 2007, 13:17

Hm, da hast du aber bei deinem Testcode einen wesentlichen Punkt nicht berücksichtigt, um den es u.a. auch ging: Du verwendest nur zwei Strings, die du zusammenfügst. Der Punkt ist aber ja gerade, dass bei mehr als zwei Strings über die einfache Konkatenation temporäre Strings erzeugt werden, aber bei '%s%s%s%s' (und auch ''.join()) jeweils nur einer.

Beispiel:

Code: Alles auswählen

# Ja, auch 'abcd' wäre eine Sequenz, aber
# das wollen wir ja erst als Ergebnis... ;)
strings = ['a', 'b', 'c', 'd']

# hier werden temporär 'ab' und 'abc' erzeugt
result1 = a + b + c + d

# hier wird nur ein String erzeugt
result2 = '%s%s%s%s' % strings

Das meint jedenfalls der von mir zitierte Auszug aus dem Styleguide.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Beitragvon sape » Mittwoch 10. Januar 2007, 13:53

Hmm, ich bin nicht sicher ob ich dich richtig verstehe.

``return x + y `` und ``return '%s%s' % (x, y)`` Bei ``[Die Laufzeit wird ermittelt]`` geben nur das verfahren an. Es werden also mehr Objekte verwendet wie ich schon schrieb und nicht nur x und y. Ich habe mir ein Script gestern geschrieben das mir 1000 Objekte mit der passenden return Zeile als Funktionsdefinition erzeugt. In etwa so sieht der Output aus:

Code: Alles auswählen

def f1():
    obj_1 = ... # Es wird ein String mit ungefähr 3000 Zeichen zugewiesen
    obj_2 = ...
    ...
    obj_999 = ...
    return obj_1 + obj_2 + ... + obj_999

Dan wird f2 definiert:

Code: Alles auswählen

def f2():
    obj_1 = ...
    ...
    obj_999
    return "%s%s%s" [i]... (<--- Also 1000  mal %s)...[/i] % (obj_1, obj_2, ..., obj_999)


...

Das ist das Script das ich für die Generierung verwendet habe (Ist schnell zusammengehackt und nicht Optimiert):

Code: Alles auswählen

MAX_OBJ = 1000

value = "".join([str(x) for x in xrange(MAX_OBJ)])
assignment_expr = list()
retval_expr = ['    return ']
retval_expr2 = list()

for i in xrange(MAX_OBJ):
    obj = "obj_%s" % str(i)
    expr = "%s%s = '%s'\n" % (' ' * 4, obj, value)
    assignment_expr.append(expr)
    retval_expr.append(obj)
    retval_expr.append(" + ")
    retval_expr2.append(obj)
    retval_expr2.append(", ")

retval_expr.pop(-1)
retval_expr2.pop(-1)
output = "def f1():\n" + "".join(assignment_expr) + "".join(retval_expr)

__ = "    return '%s' %%(" % ('%s' * MAX_OBJ) + "".join(retval_expr2) + ')'
output += "\n\ndef f2():\n" + "".join(assignment_expr) + __
f = file('ftest.py', 'w')
f.writelines(output)
f.close()


Das erzeugt Script ftest.py wird dan von folgenden Script geladen:

Code: Alles auswählen

from mylib.benchmark import Benchmark
from ftest import f1, f2

bm = Benchmark()
bm.add_function(f1, "return x + y          ")
bm.add_function(f2, "return '%s%s' % (x, y)")
bm.run()
bm.print_ranking()


lg

P.S.: benchmark.py gibt es hier:
Thread: http://www.python-forum.de/topic-7735,30.html
File: http://paste.pocoo.org/show/83/
BTW: Wo ich mir gerade noch mal das Script durchgelesen habe, fällt mir auf, dass ich die Docstrings mal in reStructuredText ändern muss und unbedingt mal ``**kwargs`` einbauen muss, damit auch keywords akzeptiert werden ^^
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Beitragvon HWK » Mittwoch 10. Januar 2007, 16:22

Das ist ja alles sehr interessant. Dass ''.join() schneller als '%s%s' und += ist wusste ich zwar schon. Die Variante, zu einer Liste hinzufügen und erst am Ende mit join() einen Gesamtstring erzeugen, ist aber für mich neu und höchst interessant.
Ich hatte ein wirkliches Geschwindigkeitsproblem in einem Terminalprogramm für die serielle Schnittstelle bei der Datenrecherche. Anfangs habe ich einfach alle Zeichen mit += gesammelt und mit if endswith('xyz')-Abfragen verarbeitet. Dabei 'gingen aber immer wieder Zeichen verloren'. Ich vermutete, dass es an den wohl notwendigen Garbage-Collections liegen könnte, und habe den Sammelstring immer auf die zur Auswertung minimal notwendige Länge per Slicing gekürzt: [code=]text = text[-laenge:] + char[/code]Aber erst nachdem ich die endswith-Abfragen nicht mehr nach jedem neuen Zeichen durchgeführt habe, sondern nur noch wenn das Zeichen 'H' ist, da die Vergleichsstrings immer mit einem 'H' enden, war die Schleife schnell genug. Ein in C geschriebenes professionelles Terminalprogramm ist aber weiterhin wesentlich schneller.
Deshalb kam mir jetzt natürlich die Idee, die Schleife mittels der Listen-Methode zu beschleunigen. Ich sehe aber keine Möglichkeit, einfach auf bestimmte Zeichenketten am Ende oder sogar innerhalb der Liste, die ja nur aus einzelnen Zeichen bestehen würde, zu testen. Hat da jemand eine gute Idee?
Ist wahrscheinlich alles sehr schwer verständlich, deshalb hier ein bisschen Pseudocode:

Code: Alles auswählen

def invest(self):
    out = ''
    text = ''
    while True:
        c = self.s.read() # Von serieller Schnittstelle lesen
        text = text[-40:] + c
        self.term.process(c) # Zeichen für Bildschirmausgabe verarbeiten
        if c != 'H':
            continue # Kann keine der gesuchten Zeichenketten sein
        if text.endswith('\x1B[23;2H<  >\x1B[23;3H\x1B[23;3H'): # Menü 1
            pass
        elif text.endswith('\x1B[23;1H<  >\x1B[23;2H\x1B[23;2H'): # Menü 2
            pass
        elif text.endswith('..\x1B[4;17H\x1B[4;17H'): # Menü 3
            pass
        elif text.endswith(self.press): # Ausgabe der Datenrecherche
            scr = self.term.GetScreen() # Bildschirminhalt kopieren
            out += scr
            self.s.write('\r\n') # Neue Seite anfordern
            if 'xyz' in scr:
                break
MfG
HWK

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot]