frage zu "print" befehl

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.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Hab jetzt mal einen eigenen Performance-Test gemacht, und String-Konkatenation ist messbar etwas schlechter wie join und String-Formatierung mit %s. Mit %d schneidet es ca. gleich ab.

Hier der Code:
http://paste.pocoo.org/show/146927/

Und die Ergebnisse:

Code: Alles auswählen

1) 164.55 usec/pass   + Konkenation
2) 151.45 usec/pass   join (Schleife)
3) 109.62 usec/pass   join (LC)

4) 2.00 usec/pass  + Konkenation
5) 2.11 usec/pass  %d Formatierung
6) 0.71 usec/pass  %s Formatierung 
(Python 2.6, Win7)
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

ice2k3 hat geschrieben:Hab jetzt mal einen eigenen Performance-Test gemacht, und String-Konkatenation ist messbar etwas schlechter wie join und String-Formatierung mit %s. Mit %d schneidet es ca. gleich ab.
Stimmt nicht in jedem Fall. Es hängt - abgesehen von der konkreten Implementierung und Python-Version - von der Länge der zu verbindenden Zeichenketten, von der Anzahl der zu verbindenen Zeichenketten und vom Datentyp der einzufügenden Werte ab.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Das war ja auch nur die Beschreibung von meinem Performance-Test.
Deshalb hab ich ja extra auch noch die Python-Version und mein OS gepostet ;)
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

ice2k3 hat geschrieben:String-Konkatenation sollte in Python nie mit +-Operator gemacht werden
Naja, die Aussage steht für mich persönlich in etwa auf einer Ebene mit "es sollte nie gegen PEP 8 verstoßen werden". Ich hatte kürzlich selber ein Snippet gepostet, wo es darum ging, einen String solange mit einer unbekannten Anzahl an Zeichen zu erweitern bis er eine bestimmte Mindestlänge hat. Es wäre da unnötig kompliziert gewesen, bei jedem Durchlauf der `while`-Schleife die Anzahl der Zeichen in allen Elementen einer Liste zusammen zu zählen.

Was entscheidenden Grund angeht, wieso man in dem Beispiel aus diesem Thread keine Konkatenation machen sollte, so schließe ich mich meinen Vorrednern an: Es geht vor allem um die Lesbarkeit. Wenn man es so sagen will, ist problembärs Vorschlag, der die Werte erstmal von Hand "zurechtcasten" muss und dann mit dem +-Operator zusammensetzt, quasi der Lowlevel-Ansatz, während man ab Python 2.6 nur noch seine geschweiften Klammern setzt, die Python dann mit den gewünschten Werten füllt. Ab Python 2.7 bzw. 3.1 (glaub ich) ist dann nicht mal mehr eine Zahl in dem Klammernpaar für den Index notwendig, wenn man das nicht braucht.

Sehr praktisch wird String Formatting in solchen Fällen:

Code: Alles auswählen

>>> class McOrder(object):
...     def __init__(self, burger, side, drink):
...         self.burger = burger
...         self.side = side
...         self.drink = drink
... 
>>> order = McOrder('Cheeseburger', 'French Fries', 'Coke')
>>> 'Your order was a {0.burger} with {0.side} and {0.drink}'.format(order)
'Your order was a Cheeseburger with French Fries and Coke'
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

snafu hat geschrieben:Ich hatte kürzlich selber ein Snippet gepostet, wo es darum ging, einen String solange mit einer unbekannten Anzahl an Zeichen zu erweitern bis er eine bestimmte Mindestlänge hat. Es wäre da unnötig kompliziert gewesen, bei jedem Durchlauf der `while`-Schleife die Anzahl der Zeichen in allen Elementen einer Liste zusammen zu zählen.
Ja, eben, wenn man auch eine Zählvariable mit der Länge nehmen könnte und diese bei jedem ``liste.append(string)`` um ``len(string)`` inkrementieren könnte. Am Schluss noch ein ``''.join(liste)`` und fertig :)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wenn man so zwanghaft `''.join()` auf Strings (verbunden mit dem Zusatzaufwand wie in meinem Beispiel) verwenden soll, dann frage ich mich, wieso der `+`-Operator bei Zeichenketten nicht einfach zu einem Alias für `''.join()` und intern eine Liste mit den Strings geführt wird. Ich finde dieses Vorgehen jedenfalls nicht gerade intuitiv und sehe auch keine enormen Performance-Einbußen, sobald man mal anders vorgeht. Ich füge jetzt aber auch nicht unbedingt eine Zeichenkette von 520KB zu einer alten Zeichenkette von 893KB hinzu, sodass ich das merken würde... *scnr*
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

snafu hat geschrieben: Ich hatte kürzlich selber ein Snippet gepostet, wo es darum ging, einen String solange mit einer unbekannten Anzahl an Zeichen zu erweitern bis er eine bestimmte Mindestlänge hat
Hast du da str.rjust() (bzw. str.ljust) nachgebaut? :wink:

scnr, Jörg
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

b.esser-wisser hat geschrieben:Hast du da str.rjust() (bzw. str.ljust) nachgebaut? :wink:
Nein, ich hab `/dev/urandom` befragt und wollte nur bestimmte Zeichen verwenden. Das Device musste halt solange gelesen werden bis die gewünschte Anzahl an verwendbaren Zeichen erreicht war.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

@snafu
Na dann - wäre ja auch zu schön gewesen :twisted:
BlackJack

Ein paar Funktionen aus `itertools` und `functools` und schon kann man das auch problemlos mit `join()` machen:

Code: Alles auswählen

In [16]: urandom_file = open('/dev/urandom', 'rb')

In [17]: random_chars = iter(partial(urandom_file.read, 1), '')

In [18]: ''.join(islice((c for c in random_chars if c < 'Z'), 10))
Out[18]: '\x19P\x10\x00 %,5\x1d6'
:-)
problembär

Vielleicht sollte man noch erwähnen, daß das Problem nur entsteht, eben weil in Python alles nett und freundlich sein soll: Deshalb denkt der print-Befehl selbst an das "\n", das man meist will, und beim "," fügt er eben noch eine Leerstelle an, wohl, weil das in den meisten Fällen auch gewollt ist.
Wenn man dieses Verhalten umgeht, weil man was anderes will, sollte man das IMHO ebenso nett und freundlich tun.

Aber ich bin da tolerant: TMTOWTDI :wink:.

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

problembär hat geschrieben:Vielleicht sollte man noch erwähnen, daß das Problem nur entsteht, eben weil in Python alles nett und freundlich sein soll: Deshalb denkt der print-Befehl selbst an das "\n", das man meist will, und beim "," fügt er eben noch eine Leerstelle an, wohl, weil das in den meisten Fällen auch gewollt ist.
Wenn man dieses Verhalten umgeht, weil man was anderes will, sollte man das IMHO ebenso nett und freundlich tun.

Code: Alles auswählen

from __future__ import print_function

print('a', 'b', end='')
print('a', 'b', sep='', end='')
Ist mir nett und freundlich genug :)
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

BlackJack hat geschrieben:Ein paar Funktionen aus `itertools` und `functools` und schon kann man das auch problemlos mit `join()` machen:
Nur, dass es überhaupt nicht das tut, was es soll. In meinem Fall sollten nur Buchstaben, Zahlen und Unterstriche herauskommen. Hier scheint alles Mögliche heraus zu kommen.
BlackJack

@snafu: Da Du nicht gesagt hast was für Bedingungen gelten sollten, kommt da "alles mögliche" heraus. Ich kann ja nicht hellsehen und habe halt eine relativ willkürliche Bedingung verwendet. Die kann man ja aber problemlos anpassen.

Code: Alles auswählen

In [24]: urandom_file = open('/dev/urandom', 'rb')

In [25]: random_chars = iter(partial(urandom_file.read, 1), '')

In [26]: ''.join(islice((c for c in random_chars if c.isalnum() or c == '_'), 10))
Out[26]: 'PkrpmRt4x_'
Antworten