Python: Schleifen iterierung Varianten

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
Chaostheorie
User
Beiträge: 1
Registriert: Freitag 11. Oktober 2019, 21:12

Ich bin seit längerem am programmieren mit Python und wollte eine Frage zur Best Practice/ effizentieren Schreibweise bei der Iterierung von Python stellen.
Normalerweise versuche ich so oft wie möglich:

Code: Alles auswählen

for record in list:
	print(record)
zu verwenden. Aber ist das wirklich besser/ macht es einen Unterschied zu:

Code: Alles auswählen

for i in range(len(list)):
	print(list[i])
Grund der Frage: Ich arbeite seit kürzerem mit einem großen Dataset und wollte aufgrund meines schwächelnden PS's vorallem bei Schleifen durch list comprehensions Zeit sparen aber ich frage mich welche der Bieden oben genannten Varianten besser währe.
Danke im Vorraus, Chaostheorie
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Die zweite Variante ist ein Anti-Pattern in Python. Es macht schlicht keinen Sinn es so zu tun.
Was schneller ist, kanst du ja einfach selbst herausfinden, indem du z.B. mit timeit die Zeit misst.
Aber wie sollte denn die zweite Variante deiner Meinung nach Zeit oder Resourcen sparen?
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Chaostheorie: List comprehensions sind nicht dazu da um Zeit zu sparen, sondern um Code lesbarer zu machen. Wobei list comprehensions auch das nicht automatisch machen, man sollte sie zum Beispiel nicht zu stark schachteln.

Wenn es lesbar geschrieben in Python zu langsam ist, dann sollte man über die Algorithmen nachdenken, einen leistungsfähigeren Rechner verwenden, oder mindestens die Teile die zu langsam sind in einer anderen Programmiersprache schreiben. Wenn man anfängt Teile des Programms aus Geschwindigkeitsgründen komplizierter und schwerer verständlich auszudrücken als man das mit idiomatischem Python machen würde, oder gar anfängt deswegen Sprachelemente für Sachen zu missbrauchen für die sie nicht gedacht sind, macht man etwas falsch.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Zur Frage "macht es einen Unterschied?" kann man sich ja einfach mal den generierten Bytecode anschauen.

Code: Alles auswählen

def do_something(data):
    for record in data:
        print(record)
liefert

Code: Alles auswählen

  2           0 SETUP_LOOP              20 (to 22)
              2 LOAD_FAST                0 (data)
              4 GET_ITER
        >>    6 FOR_ITER                12 (to 20)
              8 STORE_FAST               1 (record)

  3          10 LOAD_GLOBAL              0 (print)
             12 LOAD_FAST                1 (record)
             14 CALL_FUNCTION            1
             16 POP_TOP
             18 JUMP_ABSOLUTE            6
        >>   20 POP_BLOCK
        >>   22 LOAD_CONST               0 (None)
             24 RETURN_VALUE

Code: Alles auswählen

def do_something(data):
    for i in range(len(data)):
        print(data[i])
führt zu

Code: Alles auswählen

  2           0 SETUP_LOOP              32 (to 34)
              2 LOAD_GLOBAL              0 (range)
              4 LOAD_GLOBAL              1 (len)
              6 LOAD_FAST                0 (data)
              8 CALL_FUNCTION            1
             10 CALL_FUNCTION            1
             12 GET_ITER
        >>   14 FOR_ITER                16 (to 32)
             16 STORE_FAST               1 (i)

  3          18 LOAD_GLOBAL              2 (print)
             20 LOAD_FAST                0 (data)
             22 LOAD_FAST                1 (i)
             24 BINARY_SUBSCR
             26 CALL_FUNCTION            1
             28 POP_TOP
             30 JUMP_ABSOLUTE           14
        >>   32 POP_BLOCK
        >>   34 LOAD_CONST               0 (None)
             36 RETURN_VALUE
Man muss den Bytecode nicht mal wirklich komplett verstehen um zu sehen, dass die zweite Variante im Resultat irgendwie aufgeblähter aussieht.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Chaostheorie hat geschrieben: Freitag 11. Oktober 2019, 21:21 Ich arbeite seit kürzerem mit einem großen Dataset und wollte aufgrund meines schwächelnden PS's vorallem bei Schleifen durch list comprehensions Zeit sparen aber ich frage mich welche der Bieden oben genannten Varianten besser währe.
Keine der beiden Varianten ist eine List Comprehension. Es handelt sich im Falle von Python immer um for-each-Schleifen, d.h. die Elemente werden beim Schleifendurchlauf direkt geliefert. Im Gegensatz zur klassischen for-Schleife muss man die also nicht mehr per Indexzugriff ansprechen. Bei deiner "Simulation" der klassischen Schleife nutzt du eine for-each-Schleife über die Rückgabe von range() und die gelieferten Zahlen für den anschließenden Indexzugriff. Das ist unnötig umständlich, zeitaufwändiger und schlechter zu lesen. Daher besser gar nicht erst angewöhnen.

Zum Thema List Comprehensions findest du hier übrigens einige Infos auf deutsch:
https://py-tutorial-de.readthedocs.io/d ... rehensions

Ach ja, und für die Analyse und Manipulation größerer Datensätze eignet sich das externe Paket pandas recht gut. Das erleichtert vieles und ist - zumindest für numerische Daten - ziemlich flott, wenn man es richtig benutzt.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Ich würde empfehlen bei größeren Daten Mengen mal einen Blick auf pandas zu werfen. Wir haben da sehr gute Erfahrungen damit gesammelt um Daten im ein- bis zweistelligen GiB Bereich zu verarbeiten.
Antworten