Seite 1 von 1

Brauche bitte Hilfe

Verfasst: Sonntag 16. März 2008, 22:53
von holgi74
Hallo

habe folgendes Script, dass am Ende einen Text auf dem Bildschirm ausgibt. Ich möchte aber zusätzlich die Speicherung in eine Datei z.B. output.txt
Wer kann mir helfen?

Code: Alles auswählen

# Neuen Text erstellen

CurWort = 'Der'
LenText = 200
Text = CurWort

for n in range(LenText):
    x = random()
    ProbSum = 0
    for (NextWort, Prob) in WortDict[CurWort].items():
        if (x>=ProbSum) and (x < ProbSum+Prob):
            Text += " " + NextWort
            CurWort = NextWort
        ProbSum += Prob

print Text[:Text.rfind('.')+1]
z = raw_input('Enter beendet das Programm. ')

Verfasst: Sonntag 16. März 2008, 23:43
von Leonidas
Hallo holgi74, willkommen im Forum,

Erstmal formales: du hast ins falsche Unterforum gepostet. Ich werds verschieben, aber ändere doch bitte den Titel des Threads und schreib dort was sinnvolles rein.

Zweitens: dieser ``raw_input``-Trick um das Fenster offen zu halten funktioniert nicht immer richtig und ist auch Quatsch. Schau in die FAQ, dort steht wie man Skripte richtig startet.

Drittens: Wenn du die FAQ gelesen hast kannst du mit ``python deinskript.py > dateiname.txt`` die Ausgaben deines Programmes in eine Datei reinschreiben.

Verfasst: Sonntag 16. März 2008, 23:49
von holgi74
Danke für die Infos. Werde mir die FAQ mal in ruhe durchlesen.

Viele Grüße

Verfasst: Montag 17. März 2008, 10:40
von BlackJack
Und dann wäre ein Blick in den Style Guide vielleicht eine gute Idee.

Wenn man die Liste der Zahlen nicht braucht, ist `xrange()` speicherschonender.

Bei der Namensgebung hättest Du weniger abkürzen und Dich auf eine Sprache beschränken können, `NextWort` klingt irgendwie nicht so toll.

Aufauen einer Zeichenkette mittels wiederholtem ``+=`` kann recht ineffizient werden. Üblicherweise sammelt man die Einzelteile in einer Liste und benutzt am Ende die `join()`-Methode auf Zeichenketten.

Die ``if``-Bedingung lässt sich einfacher ohne ``and`` ausdrücken.

Ungetestet:

Code: Alles auswählen

def create_text(word2probability, length=200, start_word='Der'):
    current_word = start_word
    result = [current_word]
    for dummy in xrange(length):
        x = random()
        probability_sum = 0
        for next_word, probability in word2probability[current_word].items():
            if probability_sum < x < probability_sum + probability:
                result.append(next_word)
                current_word = next_word
            probability_sum += probability
    
    result = ' '.join(result)
    return result[:result.rfind('.') + 1]

Verfasst: Montag 17. März 2008, 12:45
von numerix
BlackJack hat geschrieben:Aufbauen einer Zeichenkette mittels wiederholtem ``+=`` kann recht ineffizient werden. Üblicherweise sammelt man die Einzelteile in einer Liste und benutzt am Ende die `join()`-Methode auf Zeichenketten.
Liest man ja immer wieder. Hab mal experimentiert:

Code: Alles auswählen

import time, profile, cProfile

def string_add():
    s = ""
    for k in xrange(anz): s+=str(k)

def list_app():
    l = list()
    for k in xrange(anz): l.append(str(k))
    s = "".join(l)

def list_comp():
    s = "".join([str(k) for k in xrange(anz)])

anz = 100000  # 100.000
profile.run("string_add(); list_app(); list_comp()")
cProfile.run("string_add(); list_app(); list_comp()")

anz = 1000000  # 1.000.000
for func in [string_add,list_app,list_comp]:
    time0 = time.time()
    func()
    print "%10s: %.2f sec" %(func.__name__,time.time()-time0)
Dabei ist folgendes herausgekommen (gekürzte Fassung):

Code: Alles auswählen

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.316    0.316    0.344    0.344 speedtest.py:12(list_comp)
        1    0.284    0.284    0.284    0.284 speedtest.py:3(string_add)
        1    1.812    1.812    3.112    3.112 speedtest.py:7(list_app)

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.266    0.266    0.285    0.285 speedtest.py:12(list_comp)
        1    0.338    0.338    0.338    0.338 speedtest.py:3(string_add)
        1    0.567    0.567    0.805    0.805 speedtest.py:7(list_app)

string_add: 3.56 sec
  list_app: 3.71 sec
 list_comp: 3.51 sec
Unterschiede in den absoluten Zeiten bei den verschiedenen Testverfahren machen mir kein Problem; aber die relativen Zeiten. Das einzige, was demnach wirklich sicher zu sein scheint, ist, dass die Variante mit dem append() die schlechteste Performance erreicht. Zeichenketten"addition" und LC tun sich wenig. Je nach "Profiler" liegt mal die eine, mal die andere vorne.

Ist mein Testverfahren grundsätzlich unbrauchbar?
Oder ist die Ergebniszeichenkette mit 488890 Zeichen immer noch zu kurz?
Gibt es andere Szenarien, wo eine Zeichenketten"addition" klar verliert?

Verfasst: Montag 17. März 2008, 13:50
von BlackJack
Nicht unbrauchbar, Du musst aber auch dazu sagen mit welcher Python-Version. Das Zeichenkettenobjekte auf die es nur eine Referenz gibt, bei dieser Operation doch "mutiert" werden, es merkt ja keiner, ist ein Implementierungsdetail von aktuellen CPython-Versionen. Man spart sich so das Erzeugen eines neuen Python-Objekts und beim `realloc()` unter der Haube müssen auch die alten Zeichenketten-Daten von der ersten Zeichenkette nicht unbedingt umkopiert werden.

Verfasst: Montag 17. März 2008, 14:01
von mkesper
pütone hat geschrieben:Gibt es andere Szenarien, wo eine Zeichenketten"addition" klar verliert?
Andere Python-Implementationen als CPython. In CPython ist es so optimiert, daß "a" + "b" keinen Overhead produziert. In anderen Implementationen (Jython, Ironpython, ...) kann das anders aussehen.

Verfasst: Montag 17. März 2008, 15:58
von Zap
Scheint das Verhalten auch OS-abhängig zu sein?
Also auf dem WindowsXP Rechner auf dem ich arbeite (CPython 2.5) kommt das hier raus:

Code: Alles auswählen

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.110    0.110    0.113    0.113 add_vs_join.py:12(list_comp)
        1    0.139    0.139    0.139    0.139 add_vs_join.py:3(string_add)
        1    0.536    0.536    0.805    0.805 add_vs_join.py:7(list_app)

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.108    0.108    0.111    0.111 add_vs_join.py:12(list_comp)
        1    0.137    0.137    0.137    0.137 add_vs_join.py:3(string_add)
        1    0.175    0.175    0.222    0.222 add_vs_join.py:7(list_app)

string_add: 6.91 sec
  list_app: 1.53 sec
 list_comp: 1.26 sec
Die Steigerung von 100.000 auf 1.000.000 Durchläufe scheint der add Funktion ganz schön zuzusetzen.

Verfasst: Montag 17. März 2008, 18:34
von numerix
Zap hat geschrieben:Scheint das Verhalten auch OS-abhängig zu sein?
Sieht ganz so aus. Bei 1 Mio. Durchläufen ergibt sich bei mir (alles auf demselben Rechner):

Code: Alles auswählen

Linux Kernel 2.6.13, CPython 2.4.1:
string_add: 2.58 sec
  list_app: 3.06 sec
 list_comp: 2.34 sec

Linux Kernel 2.6.13, CPython 2.5.1:
string_add: 3.10 sec
  list_app: 3.51 sec
 list_comp: 3.06 sec

Linux Kernel 2.6.18, CPython 2.5:
string_add: 2.88 sec
  list_app: 3.43 sec
 list_comp: 2.96 sec

Linux Kernel 2.6.22, CPython 2.5.1:
string_add: 3.27 sec
  list_app: 2.91 sec
 list_comp: 2.33 sec

Verfasst: Montag 17. März 2008, 18:58
von Leonidas
Bei mir ist die String-Methode dennoch langsamer.

Code: Alles auswählen

Linux Kernel 2.6.18, CPython 2.5.2:
string_add: 1.42 sec
  list_app: 0.85 sec
 list_comp: 0.73 sec

Linux Kernel 2.6.24, CPython 2.4.4:
string_add: 1.06 sec
  list_app: 1.04 sec
 list_comp: 0.80 sec
(könnte noch einige ähnliche Kisten testen, aber das reicht schon)