Wie kann ich eine Liste von Elementen aus einem Iterator erstellen (den Iterator in eine Liste umwandeln)?
Lesezeit: 5 Minuten
systempuntoout
Gegeben ein Iterator user_iteratorwie kann ich über den Iterator eine Liste der ausgegebenen Objekte iterieren?
Ich habe diesen Code, der zu funktionieren scheint:
user_list = [user for user in user_iterator]
Aber gibt es etwas schnelleres, besseres oder korrekteres?
Stellen Sie vor der Optimierung sicher, dass Sie einige Profile erstellt haben, um zu beweisen, dass dies wirklich der Engpass ist.
– S. Lott
24. September 2010 um 20:52 Uhr
@S.Lott. Normalerweise stimme ich dieser Einstellung zu, aber in diesem Fall sollte es sehr stilistisch optimiert werden, was es, wie so oft bei Python, auch auf Geschwindigkeit optimiert.
– Aaronasterling
24. September 2010 um 21:10 Uhr
Das OP sagte nichts über einen Engpass. Es ist eine völlig in Ordnung allgemeine Frage mit einer einfachen Antwort, es muss nicht von einer bestimmten Anwendung abhängen, die über einen Profiler ausgeführt werden kann.
– Ken Williams
19. März 2017 um 3:49 Uhr
Der kompakteste Weg ist [*iterator].
– Herausforderer5
27. März 2017 um 6:04 Uhr
Mikerobi
list(your_iterator)
Eigentlich fast immer um einiges schneller. Auch viel offensichtlicher.
– Thomas Wouters
24. September 2010 um 20:52 Uhr
@systempuntoout Es läuft vollständig in C. Das Listenverständnis ist in Python. Läuft natürlich schneller.
– Aaronasterling
24. September 2010 um 22:24 Uhr
Ich hasse es immer noch total, dass es in Python keinen besseren Weg gibt. Es ist mühsam, beide Seiten eines Ausdrucks bearbeiten zu müssen, nur um ihn segmentieren oder indizieren zu können. (sehr häufig in python3, wenn es sich um einen reinen Ausdruck wie zip oder eine Karte mit einer reinen Funktion handelt)
– Jo So
24. Oktober 2015 um 5:29 Uhr
In meinem Schnelltest [*your_iterator] schien etwa doppelt so schnell zu sein wie list(your_iterator). Stimmt das generell oder war es nur ein bestimmter Anlass? (Ich habe eine map als Iterator.)
– Neinstein
10. September 2018 um 21:49 Uhr
@Bachsau: Zugegeben, es ist ziemlich gut, aber vergleichen Sie es mit Bash-Skripten, bei denen Sie die aktuelle Ausgabe manipulieren können, indem Sie eine Pipe und einen weiteren Filterbefehl genau rechts vom aktuellen Befehl anhängen. Es ist ärgerlich, dass Sie für eine so kleine Unterscheidung (Iterator vs. materialisierte Liste) oft den Cursor zurückbewegen müssen.
– Jo So
25. September 2019 um 13:19 Uhr
Kederrac
seit Python 3.5 Sie können verwenden * Iterierbarer Entpackoperator:
user_list = [*your_iterator]
aber der pythonische Weg, es zu tun, ist:
user_list = list(your_iterator)
Bitte posten Sie die Ergebnisse eines Geschwindigkeitstests für mehr Punkte!
– Robino
15. Oktober 2020 um 8:34 Uhr
@Robino danke für den Vorschlag, Sie können stackoverflow.com/a/64512225/3161575 überprüfen
– kederrac
24. Oktober 2020 um 10:12 Uhr
Kederrac
@Robino schlug vor, einige sinnvolle Tests hinzuzufügen, also ist hier ein einfacher Benchmark zwischen 3 möglichen Wegen (vielleicht die am häufigsten verwendeten), um einen Iterator in eine Liste umzuwandeln:
from simple_benchmark import BenchmarkBuilder
from heapq import nsmallest
b = BenchmarkBuilder()
@b.add_function()
def convert_by_type_constructor(size):
list(iter(range(size)))
@b.add_function()
def convert_by_list_comprehension(size):
[e for e in iter(range(size))]
@b.add_function()
def convert_by_unpacking(size):
[*iter(range(size))]
@b.add_arguments('Convert an iterator to a list')
def argument_provider():
for exp in range(2, 22):
size = 2**exp
yield size, size
r = b.run()
r.plot()
Wie Sie sehen können, ist es sehr schwierig, zwischen der Konvertierung durch den Konstruktor und der Konvertierung durch Entpacken zu unterscheiden, die Konvertierung durch Listenverständnis ist der „langsamste“ Ansatz.
Ich habe auch verschiedene Python-Versionen (3.6, 3.7, 3.8, 3.9) getestet, indem ich das folgende einfache Skript verwendet habe:
import argparse
import timeit
parser = argparse.ArgumentParser(
description='Test convert iterator to list')
parser.add_argument(
'--size', help='The number of elements from iterator')
args = parser.parse_args()
size = int(args.size)
repeat_number = 10000
# do not wait too much if the size is too big
if size > 10000:
repeat_number = 100
def test_convert_by_type_constructor():
list(iter(range(size)))
def test_convert_by_list_comprehension():
[e for e in iter(range(size))]
def test_convert_by_unpacking():
[*iter(range(size))]
def get_avg_time_in_ms(func):
avg_time = timeit.timeit(func, number=repeat_number) * 1000 / repeat_number
return round(avg_time, 6)
funcs = [test_convert_by_type_constructor,
test_convert_by_unpacking, test_convert_by_list_comprehension]
print(*map(get_avg_time_in_ms, funcs))
Das Skript wird über einen Unterprozess von einem Jupyter Notebook (oder einem Skript) ausgeführt, der Größenparameter wird über Befehlszeilenargumente übergeben und die Skriptergebnisse werden der Standardausgabe entnommen.
from subprocess import PIPE, run
import pandas
simple_data = {'constructor': [], 'unpacking': [], 'comprehension': [],
'size': [], 'python version': []}
size_test = 100, 1000, 10_000, 100_000, 1_000_000
for version in ['3.6', '3.7', '3.8', '3.9']:
print('test for python', version)
for size in size_test:
command = [f'python{version}', 'perf_test_convert_iterator.py', f'--size={size}']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
constructor, unpacking, comprehension = result.stdout.split()
simple_data['constructor'].append(float(constructor))
simple_data['unpacking'].append(float(unpacking))
simple_data['comprehension'].append(float(comprehension))
simple_data['python version'].append(version)
simple_data['size'].append(size)
df_ = pandas.DataFrame(simple_data)
df_
Sie können mein vollständiges Notizbuch von erhalten Hier.
In den meisten Fällen, in meinen Tests, zeigt sich, dass das Entpacken schneller ist, aber der Unterschied ist so gering, dass sich die Ergebnisse von einem Lauf zum anderen ändern können. Auch hier ist der Verständnisansatz am langsamsten, tatsächlich sind die anderen 2 Methoden bis zu ~ 60% schneller.
14486800cookie-checkWie kann ich eine Liste von Elementen aus einem Iterator erstellen (den Iterator in eine Liste umwandeln)?yes
Stellen Sie vor der Optimierung sicher, dass Sie einige Profile erstellt haben, um zu beweisen, dass dies wirklich der Engpass ist.
– S. Lott
24. September 2010 um 20:52 Uhr
@S.Lott. Normalerweise stimme ich dieser Einstellung zu, aber in diesem Fall sollte es sehr stilistisch optimiert werden, was es, wie so oft bei Python, auch auf Geschwindigkeit optimiert.
– Aaronasterling
24. September 2010 um 21:10 Uhr
Das OP sagte nichts über einen Engpass. Es ist eine völlig in Ordnung allgemeine Frage mit einer einfachen Antwort, es muss nicht von einer bestimmten Anwendung abhängen, die über einen Profiler ausgeführt werden kann.
– Ken Williams
19. März 2017 um 3:49 Uhr
Der kompakteste Weg ist
[*iterator]
.– Herausforderer5
27. März 2017 um 6:04 Uhr