Liste Anlama vs Jeneratör İfadeler

oy
317

Ne zaman jeneratör ifadeler kullanmak gerekir ve ne zaman Python liste türetimi kullanmalıyım?

# Generator expression
(x*2 for x in range(256))

# List comprehension
[x*2 for x in range(256)]
Oluştur 06/09/2008 saat 19:07
kaynak kullanıcı
Diğer dillerde...                            


9 cevaplar

oy
76

Sonuç birden çok kez iterated gerektiğinde, veya hız ihtiyacının öncelikli olduğu liste türetimi kullanın. aralık büyük veya sonsuz jeneratör ifadeleri kullanın.

Cevap 06/09/2008 saat 19:10
kaynak kullanıcı

oy
140

Yineleme jeneratör ifade veya liste anlama aynı şeyi yapacağız. Ancak, liste anlama iken ilk bellekte tüm listeyi yaratacak jeneratör ifade anında öğeleri oluşturmak, böylece çok büyük (ve ayrıca sonsuz!) Dizileri için kullanmak mümkün.

Cevap 06/09/2008 saat 19:11
kaynak kullanıcı

oy
225

John cevabı (senin bir işi birden çok kez üzerinde yineleme istediğinizde bu liste comprehensions iyidir) iyidir. Ancak, aynı zamanda liste yöntemlerinden herhangi birini kullanmak istiyorsanız bir liste kullanması gerektiğini belirtmek gerekir. Örneğin, aşağıdaki kod çalışmaz:

def gen():
    return (something for something in get_some_stuff())

print gen()[:2]     # generators don't support indexing or slicing
print [5,6] + gen() # generators can't be added to lists

Yaptığınız tüm zamanlar yineleme eğer Temelde, bir jeneratör ifadesini kullanın. depolamak ve oluşturulan sonuçları kullanmak istiyorsanız, o zaman bir liste anlayışı ile kapalı muhtemelen daha iyi.

Performans birinden birini seçmek için en yaygın nedeni olduğundan, benim tavsiyem bu konuda endişe ve sadece seçeceğiz getirmemektir; Eğer programı çok yavaş, daha sonra çalıştığı ve ancak o zaman geri dönüp kodunuzu akort dert gerektiğini bulursanız.

Cevap 06/09/2008 saat 19:54
kaynak kullanıcı

oy
3

Bazen kurtulabiliriz tee gelen fonksiyonu itertools , bağımsız kullanılabilen aynı jeneratörü için birden yineleyicinızı döndürür.

Cevap 09/09/2008 saat 23:58
kaynak kullanıcı

oy
40

Bir jeneratör ifade yararı kerede tüm listeyi oluşturmak olmaması sebebiyle daha az bellek kullanır. Liste aracı böyle sonuçlar toplayarak veya sonuçlarının dışında bir dicti oluşturma gibi olduğunda Jeneratör ifadeler iyi kullanılır.

Örneğin:

sum(x*2 for x in xrange(256))

dict( ((k, some_func(k) for k in some_list_of_keys) )

avantajı listesi tamamen oluşturulmaz olduğu vardır ve bu nedenle çok az bellek kullanılır (ve aynı zamanda daha hızlı olmalıdır)

İstenen son ürün listesi olduğunda, gerçi, liste kullanmalıdır. Sen oluşturulan liste istedikleri için, jeneratör ifadeler kullanarak herhangi memeory kurtarmaya gidiş değildir. Ayrıca sıralanmış veya ters gibi liste herhangi bir işlevi kullanmak mümkün olmanın yararı olsun.

Örneğin:

reversed( [x*2 for x in xrange(256)] )
Cevap 10/10/2008 saat 00:42
kaynak kullanıcı

oy
44

Önemli olan nokta liste anlama yeni bir liste oluşturur olmasıdır. jeneratör "filtre" kaynak malzemesi on-the-fly Eğer bit tüketir gibi bir iterable nesne oluşturur.

Eğer "hugefile.txt" adlı bir 2TB günlük dosyası varsa ve kelime "GİRİŞ" ile başlayan tüm hatlar için içerik ve uzunluğunu istediğiniz düşünün.

Yani bir liste anlama yazarak dışarı başlatmayı deneyin:

logfile = open("hugefile.txt","r")
entry_lines = [(line,len(line)) for line in logfile if line.startswith("ENTRY")]

Bu, tüm dosyayı yukarı slurps her satırı işler ve dizide eşleşen satırları saklar. Bu dizi, bu nedenle içeriğin 2 TB kadar içerebilir. Muhtemelen senin amaçlar için pratik değildir RAM bir çok şey var ve.

Bunun yerine bizim içeriğe bir "filtre" uygulamak için bir jeneratör kullanabilirsiniz. Biz sonucun üzerinde yineleme başlayana dek hiçbir veri gerçekten okunur.

logfile = open("hugefile.txt","r")
entry_lines = ((line,len(line)) for line in logfile if line.startswith("ENTRY"))

Hatta tek bir satır henüz bizim dosyadan okundu. Aslında, biz daha da ileri bizim sonucunu filtre uygulamak istediğiniz ki:

long_entries = ((line,length) for (line,length) in entry_lines if length > 80)

Hala hiçbir şey okundu, ama biz istedikleri gibi verilerimize hareket edecek şimdi iki jeneratör belirlediniz.

başka bir dosyaya bizim filtrelenmiş hatları yazmak sağlar:

outfile = open("filtered.txt","a")
for entry,length in long_entries:
    outfile.write(entry)

Şimdi biz girdi dosyasını okuyun. Bizim gibi fordöngü ek satırlar talep devam ediyor long_entriesjeneratör gelen satırları talep entry_linesuzunluğu 80 karakterden daha büyük olduğu sadece bu dönen, jeneratör. Ve sırayla, entry_linesjeneratör dan (belirtildiği gibi süzülmüş) satırları istediğinde logfilesırayla dosyasını okur yineleyici.

Bunun yerine tam doldurulmuş listede şeklinde çıktı işlevine verileri "itme" nin, onun yalnızca gerektiğinde verileri "çekme" bir yolu çıkış fonksiyonunu veriyoruz. Bu bizim durumumuzda çok daha verimli, ama oldukça gibi esnektir. Jeneratörler tek yönlü, tek bir geçiş; biz okudum günlük dosyasından veri hemen atılır alır, bu yüzden bir önceki satıra geri gidemez. Öte yandan, biz onunla bitti kez etrafında verileri koruma konusunda endişelenmenize gerek yok.

Cevap 04/04/2014 saat 08:14
kaynak kullanıcı

oy
4

Ben kullanıyorum Hadoop kıymalı modülü . Bu not ait çekmek için harika bir örnek olduğunu düşünüyorum:

import mincemeat

def mapfn(k,v):
    for w in v:
        yield 'sum',w
        #yield 'count',1


def reducefn(k,v): 
    r1=sum(v)
    r2=len(v)
    print r2
    m=r1/r2
    std=0
    for i in range(r2):
       std+=pow(abs(v[i]-m),2)  
    res=pow((std/r2),0.5)
    return r1,r2,res

İşte jeneratör (15GB kadar büyük) bir metin dosyasına dışına numaralarını alır ve Hadoop haritasında-azaltmak kullananlar numaraları basit matematik uygular. Ben verim fonksiyonu kullanılmaz, ama bunun yerine bir liste anlama, o toplamları hesaplama çok daha uzun zaman almış ve ortalama olsaydı (boşluk karmaşıklığını saymıyorum).

Hadoop Jeneratörler tüm avantajlarını kullanmak için harika bir örnek.

Cevap 04/01/2016 saat 18:31
kaynak kullanıcı

oy
9

(Bir liste gibi) değişken nesneden bir jeneratör oluştururken jeneratör değil, jeneratörün oluşturma sırasında jeneratörü kullanılarak her seferinde listesinin durumuna değerlendirilir alacak unutmayın:

>>> mylist = ["a", "b", "c"]
>>> gen = (elem + "1" for elem in mylist)
>>> mylist.clear()
>>> for x in gen: print (x)
# nothing

Orada modifiye alma listenizin herhangi bir şans (veya o listeye içinde değişebilir nesne) ama jeneratörün yaratılmasını durumunu gerekiyorsa bunun yerine bir liste anlama kullanmak gerekir.

Cevap 12/03/2016 saat 20:21
kaynak kullanıcı

oy
0

ne kadar yararlı [(ITER içinde x exp)] ile ilgili hem de iyi alır. jeneratör anlama hem de liste yöntemlerinden Performans

Cevap 16/03/2019 saat 05:57
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more