Kiedy nie jest dobry czas na korzystanie z generatorów Pythona?
Jest to raczej odwrotność do czego można używać funkcji generatora Pythona?: Generatory Pythona, wyrażenia generatora i moduł itertools
to niektóre z moich ulubionych funkcji Pythona w dzisiejszych czasach. Są one szczególnie przydatne podczas konfigurowania łańcuchów operacji do wykonywania na dużej stercie danych - często używam ich podczas przetwarzania plików DSV.
Kiedy więc Nie jest dobry czas na użycie generatora, wyrażenia generatora, czy itertools
funkcja?
- Kiedy powinienem preferować
zip()
naditertools.izip()
, czy -
range()
overxrange()
, or -
[x for x in foo]
over(x for x in foo)
?
Oczywiście, w końcu musimy "rozwiązać" generator w rzeczywiste dane, Zwykle poprzez utworzenie listy lub iterację nad nią za pomocą pętli nie-generatora. Czasami po prostu musimy znać długość. Nie o to proszę.
Używamy generatorów, aby nie przypisywać nowych list do pamięci dla tymczasowych danych. To szczególnie ma to sens w przypadku dużych zbiorów danych. Czy ma to sens również dla małych zbiorów danych? Czy istnieje zauważalna wymiana pamięci / procesora?
Jestem szczególnie zainteresowany, jeśli ktoś zrobił jakieś profilowanie na ten temat, w świetle otwierającej Oczy dyskusji list comprehension performance vs. map () i filter () . (alt link)
9 answers
Użyj listy zamiast generatora, gdy:
1) Musisz uzyskać dostęp do danych wiele razy (tzn. buforować wyniki zamiast je przekomputowywać):
for i in outer: # used once, okay to be a generator or return a list
for j in inner: # used multiple times, reusing a list is better
...
2) Potrzebujesz dostępu losowego (lub dowolnego dostępu innego niż kolejność Sekwencyjna forward):
for i in reversed(data): ... # generators aren't reversible
s[i], s[j] = s[j], s[i] # generators aren't indexable
3) Musisz dołączyć ciągi znaków (które wymagają dwóch przejść nad danymi):
s = ''.join(data) # lists are faster than generators in this use case
4) używasz PyPy które czasami nie mogą zoptymalizować kodu generatora tak bardzo, jak to możliwe z normalnymi wywołaniami funkcji i manipulacjami list.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-30 05:59:33
Ogólnie rzecz biorąc, nie używaj generatora, gdy potrzebujesz operacji na liście, takich jak len (), reversed () i tak dalej.
Mogą być również sytuacje, w których nie chcesz leniwej oceny (np. wykonać wszystkie obliczenia z góry, aby móc zwolnić zasób). W takim przypadku wyrażenie listy może być lepsze.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-29 04:42:05
Profil, Profil, Profil.
Profilowanie kodu jest jedynym sposobem, aby wiedzieć, czy to, co robisz, ma jakikolwiek wpływ.
Większość zastosowań xrange, Generatory, itp są ponad statyczne wielkości, małe zbiory danych. Dopiero gdy dotrzesz do dużych zbiorów danych, to naprawdę robi różnicę. range () vs. xrange() to głównie kwestia uczynienia kodu trochę brzydszym i nie utraty niczego, a może zyskania czegoś.
Profil, Profil, Profil.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-29 11:37:31
You should never favor zip
over izip
, range
over xrange
, lub list comprehensions over generator comprehensions. W Pythonie 3.0 range
ma xrange
-Jak semantyka i zip
mA izip
-Jak semantyka.
Składanie List jest w rzeczywistości bardziej przejrzyste, jak list(frob(x) for x in foo)
w tych czasach, gdy potrzebujesz rzeczywistej listy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-06 19:12:51
Jeśli chodzi o wydajność: jeśli używasz psyco, listy mogą być nieco szybsze niż Generatory. W poniższym przykładzie listy są o prawie 50% szybsze podczas korzystania z psyco.full ()
import psyco
import time
import cStringIO
def time_func(func):
"""The amount of time it requires func to run"""
start = time.clock()
func()
return time.clock() - start
def fizzbuzz(num):
"""That algorithm we all know and love"""
if not num % 3 and not num % 5:
return "%d fizz buzz" % num
elif not num % 3:
return "%d fizz" % num
elif not num % 5:
return "%d buzz" % num
return None
def with_list(num):
"""Try getting fizzbuzz with a list comprehension and range"""
out = cStringIO.StringIO()
for fibby in [fizzbuzz(x) for x in range(1, num) if fizzbuzz(x)]:
print >> out, fibby
return out.getvalue()
def with_genx(num):
"""Try getting fizzbuzz with generator expression and xrange"""
out = cStringIO.StringIO()
for fibby in (fizzbuzz(x) for x in xrange(1, num) if fizzbuzz(x)):
print >> out, fibby
return out.getvalue()
def main():
"""
Test speed of generator expressions versus list comprehensions,
with and without psyco.
"""
#our variables
nums = [10000, 100000]
funcs = [with_list, with_genx]
# try without psyco 1st
print "without psyco"
for num in nums:
print " number:", num
for func in funcs:
print func.__name__, time_func(lambda : func(num)), "seconds"
print
# now with psyco
print "with psyco"
psyco.full()
for num in nums:
print " number:", num
for func in funcs:
print func.__name__, time_func(lambda : func(num)), "seconds"
print
if __name__ == "__main__":
main()
Wyniki:
without psyco
number: 10000
with_list 0.0519102208309 seconds
with_genx 0.0535933367509 seconds
number: 100000
with_list 0.542204280744 seconds
with_genx 0.557837353115 seconds
with psyco
number: 10000
with_list 0.0286369007033 seconds
with_genx 0.0513424889137 seconds
number: 100000
with_list 0.335414877839 seconds
with_genx 0.580363490491 seconds
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-30 14:38:40
Jak wspominasz, "to szczególnie ma sens dla dużych zbiorów danych", myślę, że to odpowiada na twoje pytanie.
Jeśli nie trafiasz żadnych ścian, pod względem wydajności, nadal możesz trzymać się list i standardowych funkcji. Następnie, gdy napotkasz problemy z wydajnością, dokonaj przełącznika.
Jak wspomniał @u0b34a0f6ae w komentarzach, jednak korzystanie z generatorów na początku może ułatwić skalowanie do większych zbiorów danych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-26 00:19:05
Powinieneś preferować składanie list, jeśli chcesz zachować wartości dla czegoś innego później, a rozmiar Twojego zestawu nie jest zbyt duży.
Na przykład: tworzysz listę, którą będziesz pętlować kilka razy później w swoim programie.
Do pewnego stopnia można myśleć o generatorach jako zastępstwie iteracji (pętli) vs.list comprehensions jako rodzaju inicjalizacji struktury danych. Jeśli chcesz zachować strukturę danych, użyj list compenensions.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-31 16:21:02
Jeśli chodzi o wydajność, nie przychodzi mi do głowy, że chciałbyś użyć listy zamiast generatora.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-29 11:44:06
Nigdy nie znalazłem sytuacji, w której Generatory utrudniałyby to, co próbujesz zrobić. Istnieje jednak wiele przypadków, w których korzystanie z generatorów nie pomogłoby Ci bardziej niż nie Korzystanie z nich.
Na przykład:
sorted(xrange(5))
Nie oferuje żadnej poprawy w stosunku do:
sorted(range(5))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-29 16:44:36