Γεννήτρια εκφράσεις εναντίον Λίστα Κατανόηση

ψήφοι
317

Πότε θα πρέπει να χρησιμοποιείτε εκφράσεις γεννήτρια και πότε πρέπει να χρησιμοποιήσετε λίστα Η κατανόηση στην Python;

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

# List comprehension
[x*2 for x in range(256)]
Δημοσιεύθηκε 06/09/2008 στις 19:07
πηγή χρήστη
Σε άλλες γλώσσες...                            


9 απαντήσεις

ψήφοι
76

Χρησιμοποιήστε τη λίστα Η κατανόηση όταν πρέπει το αποτέλεσμα να επαναλαμβάνεται πάνω πολλές φορές, ή όταν η ταχύτητα είναι υψίστης σημασίας. Χρησιμοποιήστε εκφράσεις γεννήτρια, όπου το εύρος είναι μεγάλο ή άπειρο.

Απαντήθηκε 06/09/2008 στις 19:10
πηγή χρήστη

ψήφοι
140

Επανάληψη κατά την έκφραση της γεννήτριας ή του καταλόγου κατανόηση θα κάνει το ίδιο πράγμα. Ωστόσο, η λίστα κατανόηση θα δημιουργήσει ολόκληρη τη λίστα στη μνήμη πρώτη, ενώ η έκφραση γεννήτρια θα δημιουργήσει τα στοιχεία σε ώρα πτήσης, έτσι ώστε να είναι σε θέση να το χρησιμοποιήσει για πολύ μεγάλο (αλλά και άπειρη!) Ακολουθίες.

Απαντήθηκε 06/09/2008 στις 19:11
πηγή χρήστη

ψήφοι
225

απάντηση του Ιωάννη είναι καλό (ότι Η κατανόηση λίστας είναι καλύτερη όταν θέλετε να επαναλάβει για κάτι πολλές φορές). Ωστόσο, είναι επίσης αξίζει να σημειωθεί ότι θα πρέπει να χρησιμοποιήσετε μια λίστα, αν θέλετε να χρησιμοποιήσετε οποιαδήποτε από τις μεθόδους λίστα. Για παράδειγμα, ο κώδικας που ακολουθεί δεν θα λειτουργήσει:

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

Βασικά, χρησιμοποιήστε μια έκφραση γεννήτρια αν το μόνο που κάνετε είναι επανάληψη μία φορά. Αν θέλετε να αποθηκεύσετε και να χρησιμοποιήσετε τα παραγόμενα αποτελέσματα, τότε είστε πιθανώς καλύτεροι με μια λίστα κατανόηση.

Δεδομένου ότι η απόδοση είναι η πιο κοινή αιτία για να επιλέξετε ένα πάνω στο άλλο, η συμβουλή μου είναι να μην ανησυχείτε γι 'αυτό και μόλις πάρει ένα? αν διαπιστώσετε ότι το πρόγραμμά σας τρέχει πολύ αργά, τότε και μόνο τότε θα πρέπει να πάτε πίσω και να ανησυχείτε για το συντονισμό κωδικό σας.

Απαντήθηκε 06/09/2008 στις 19:54
πηγή χρήστη

ψήφοι
3

Μερικές φορές μπορείτε να πάρετε μακριά με το ΤΕΕ λειτουργία από itertools , επιστρέφει πολλαπλές επαναλήπτες για την ίδια γεννήτρια που μπορεί να χρησιμοποιηθεί ανεξάρτητα.

Απαντήθηκε 09/09/2008 στις 23:58
πηγή χρήστη

ψήφοι
40

Το όφελος της έκφρασης γεννήτριας είναι ότι χρησιμοποιεί λιγότερη μνήμη, δεδομένου ότι δεν χτίσει όλη τη λίστα με τη μία. Οι εκφράσεις γεννήτρια χρησιμοποιείται καλύτερα όταν η λίστα είναι ένας ενδιάμεσος, όπως αθροίζοντας τα αποτελέσματα, ή τη δημιουργία ενός dict από τα αποτελέσματα.

Για παράδειγμα:

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

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

Το πλεονέκτημα είναι εκεί ότι ο κατάλογος δεν παράγεται τελείως, και έτσι λίγο μνήμη χρησιμοποιείται (και θα πρέπει επίσης να είναι ταχύτερη)

Θα πρέπει, όμως, να χρησιμοποιήσετε λίστα Η κατανόηση όταν το επιθυμητό τελικό προϊόν είναι μια λίστα. Δεν πρόκειται να αποθηκεύσετε οποιαδήποτε memeory χρησιμοποιώντας εκφράσεις γεννήτρια, δεδομένου ότι θέλετε την παραγόμενη λίστα. Μπορείτε επίσης να πάρετε το πλεονέκτημα να είναι σε θέση να χρησιμοποιήσει οποιαδήποτε από τις λειτουργίες κατάλογος, όπως ταξινομηθεί ή να αναστραφεί.

Για παράδειγμα:

reversed( [x*2 for x in xrange(256)] )
Απαντήθηκε 10/10/2008 στις 00:42
πηγή χρήστη

ψήφοι
44

Το σημαντικό σημείο είναι ότι η λίστα κατανόησης δημιουργεί μια νέα λίστα. Η γεννήτρια δημιουργεί ένα iterable αντικείμενο που θα «φίλτρο» η ύλη on-the-fly όπως μπορείτε να καταναλώνετε τα κομμάτια.

Φανταστείτε ότι έχετε ένα αρχείο καταγραφής 2TB που ονομάζεται «hugefile.txt», και θέλετε το περιεχόμενο και τη διάρκεια για όλες τις γραμμές που ξεκινούν με τη λέξη «ENTRY».

Έτσι, μπορείτε να δοκιμάσετε ξεκινάμε γράφοντας μια λίστα με κατανόηση:

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

Αυτό slurps ασφαλείας ολόκληρου του αρχείου, επεξεργάζεται κάθε γραμμή, και αποθηκεύει τις γραμμές που ταιριάζουν σε σειρά σας. Αυτός ο πίνακας θα μπορούσε, επομένως, να περιέχει έως και 2TB του περιεχομένου. Αυτό δεν είναι πολύ RAM, και κατά πάσα πιθανότητα πρακτικό για τους σκοπούς σας.

Έτσι, αντί να μπορούμε να χρησιμοποιήσουμε μια γεννήτρια για να εφαρμόσει ένα «φίλτρο» για το περιεχόμενό μας. Δεν υπάρχουν δεδομένα είναι στην πραγματικότητα διαβάσει μέχρι να ξεκινήσει επανάληψη πάνω από το αποτέλεσμα.

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

Ούτε καν μια ενιαία γραμμή έχει διαβάσει από το αρχείο μας ακόμα. Στην πραγματικότητα, λένε θέλουμε να φιλτράρετε αποτέλεσμα μας ακόμη περισσότερο:

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

Ακόμα τίποτα δεν έχει διαβάσει, αλλά έχουμε διευκρινίζεται τώρα δύο γεννήτριες που θα λειτουργήσει για τα δεδομένα μας όπως θέλουμε.

Αφήνει να γράψουν φιλτράρεται γραμμές μας σε ένα άλλο αρχείο:

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

Τώρα διαβάζουμε το αρχείο εισόδου. Όπως μας forβρόχος συνεχίζει να ζητήσει πρόσθετες γραμμές, η long_entriesγεννήτρια απαιτεί γραμμών από την entry_linesγεννήτρια, επιστρέφοντας μόνο εκείνοι των οποίων το μήκος είναι μεγαλύτερο από 80 χαρακτήρες. Και με τη σειρά της, η entry_linesγεννήτρια ζητά γραμμές (φιλτράρεται όπως φαίνεται) από το logfileiterator, το οποίο με τη σειρά του διαβάζει το αρχείο.

Έτσι, αντί να «πιέζει» τα στοιχεία για την λειτουργία εξόδου σας, με τη μορφή ενός πλήρως κατοικείται λίστα, δίνετε τη λειτουργία εξόδου ένας τρόπος για να «τραβήξει» τα δεδομένα μόνο όταν χρειάζεται τους. Αυτό είναι στην περίπτωσή μας πολύ πιο αποτελεσματική, αλλά δεν είναι τόσο ευέλικτο. Γεννήτριες είναι ένας τρόπος, ένα πέρασμα? τα δεδομένα από το αρχείο καταγραφής που έχουμε διαβάσει παίρνει αμέσως απορρίπτεται, οπότε δεν μπορούμε να πάμε πίσω σε μια προηγούμενη γραμμή. Από την άλλη πλευρά, δεν έχετε να ανησυχείτε για τη διατήρηση των δεδομένων γύρω από τη στιγμή που θα τελειώσετε με αυτό.

Απαντήθηκε 04/04/2014 στις 08:14
πηγή χρήστη

ψήφοι
4

Είμαι με τη χρήση της μονάδας Hadoop Κιμάς . Νομίζω ότι αυτό είναι ένα πολύ καλό παράδειγμα για να λάβει υπόψη της:

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

Εδώ η γεννήτρια παίρνει αριθμών από ένα αρχείο κειμένου (τόσο μεγάλη όσο 15GB) και εφαρμόζει απλές μαθηματικές πράξεις για αυτούς τους αριθμούς χρησιμοποιώντας Hadoop του χάρτη-μείωση. Αν και δεν είχα χρησιμοποιήσει τη λειτουργία απόδοσης, αλλά αντ 'αυτού μια λίστα με κατανόηση, θα έχουν πολύ περισσότερο χρόνο για τον υπολογισμό των ποσών και η μέση (για να μην αναφέρουμε το χώρο πολυπλοκότητα).

Hadoop είναι ένα μεγάλο παράδειγμα για τη χρήση όλα τα πλεονεκτήματα των γεννητριών.

Απαντήθηκε 04/01/2016 στις 18:31
πηγή χρήστη

ψήφοι
9

Όταν δημιουργείτε μια γεννήτρια από ένα μεταβλητό αντικείμενο (όπως μια λίστα) να γνωρίζουν ότι η γεννήτρια θα πάρει αξιολογήθηκαν για την κατάσταση της λίστας σε χρόνο χρησιμοποιώντας τη γεννήτρια, όχι κατά τη στιγμή της δημιουργίας της γεννήτριας:

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

Εάν υπάρχει οποιαδήποτε πιθανότητα της λίστας σας να τροποποιηθεί (ή ένα μεταβλητό αντικείμενο στο εσωτερικό του καταλόγου αυτού), αλλά θα πρέπει να έχετε την κατάσταση στην δημιουργία της γεννήτριας θα πρέπει να χρησιμοποιήσετε μια λίστα κατανόηση αντ 'αυτού.

Απαντήθηκε 12/03/2016 στις 20:21
πηγή χρήστη

ψήφοι
0

πώς σχετικά με τη χρήση [(exp για το x στο ITER)] για να πάρει το καλό και των δύο. Απόδοση από την κατανόηση της γεννήτριας, καθώς και κατάλογος των μεθόδων

Απαντήθηκε 16/03/2019 στις 05:57
πηγή χρήστη

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