Στην Python, είναι απλό να χρησιμοποιήσετε τη σημειογραφία της κατανόησης λίστας όταν δημιουργείτε μια νέα λίστα.(List comprehensions
)
- 5. Data Structures — List Comprehensions — Python 3.10.0 Documentation
- 6. Expressions — Displays for lists, sets and dictionaries — Python 3.10.0 Documentation
Σε αυτό το άρθρο, θα συζητήσουμε πρώτα τα εξής
- Βασικός τύπος συμβολισμού κατανόησης λίστας
- Συμβολισμός κατανόησης λίστας με διακλάδωση υπό όρους με if
- Συνδυασμός με τριμερείς τελεστές (επεξεργασία τύπου if else)
zip()
,enumerate()
Συνδυασμός με αυτά- συμβολισμός συμπερίληψης εμφωλευμένης λίστας
Στη συνέχεια, θα εξηγήσουμε το σύνολο των συμβολισμών κατανόησης λίστας με δείγμα κώδικα.
- συμβολισμός συμπερίληψης συνόλου(
Set comprehensions
) - συμβολισμός συμπερίληψης λεξικού(
Dict comprehensions
) - τύπος γεννήτριας(
Generator expressions
)
- Βασικός τύπος συμβολισμού κατανόησης λίστας
- Συμβολισμός κατανόησης λίστας με διακλάδωση υπό όρους με if
- Συνδυασμός με τριμερείς τελεστές (επεξεργασία τύπου if else)
- Συνδυασμός με zip() και enumerate()
- συμβολισμός συμπερίληψης εμφωλευμένης λίστας
- συμβολισμός συμπερίληψης συνόλου(Set comprehensions)
- συμβολισμός συμπερίληψης λεξικού(Dict comprehensions)
- τύπος γεννήτριας(Generator expressions)
Βασικός τύπος συμβολισμού κατανόησης λίστας
Ο συμβολισμός της κατανόησης λίστας γράφεται ως εξής.
[Expression for Any Variable Name in Iterable Object]
Παίρνει κάθε στοιχείο ενός επαναληπτικού αντικειμένου, όπως μια λίστα, πλειάδα ή περιοχή, με ένα αυθαίρετο όνομα μεταβλητής και το αξιολογεί με μια έκφραση. Επιστρέφεται μια νέα λίστα με το αποτέλεσμα της αξιολόγησης ως στοιχείο.
Δίνεται ένα παράδειγμα μαζί με μια ισοδύναμη δήλωση for.
squares = [i**2 for i in range(5)]
print(squares)
# [0, 1, 4, 9, 16]
squares = []
for i in range(5):
squares.append(i**2)
print(squares)
# [0, 1, 4, 9, 16]
Η ίδια διαδικασία μπορεί να γίνει και με τη map(), αλλά προτιμάται ο συμβολισμός κατανόησης λίστας για την απλότητα και τη σαφήνειά του.
Συμβολισμός κατανόησης λίστας με διακλάδωση υπό όρους με if
Είναι επίσης δυνατή η διακλάδωση υπό όρους με το if. Γράψτε το if στο postfix ως εξής.
[Expression for Any Variable Name in Iterable Object if Conditional Expression]
Μόνο τα στοιχεία του αντικειμένου iterable των οποίων η υπό συνθήκη έκφραση είναι αληθής αξιολογούνται από την έκφραση και επιστρέφεται μια νέα λίστα της οποίας τα στοιχεία είναι το αποτέλεσμα.
Μπορείτε να χρησιμοποιήσετε οποιοδήποτε όνομα μεταβλητής στην υπό συνθήκη έκφραση.
Δίνεται ένα παράδειγμα μαζί με μια ισοδύναμη δήλωση for.
odds = [i for i in range(10) if i % 2 == 1]
print(odds)
# [1, 3, 5, 7, 9]
odds = []
for i in range(10):
if i % 2 == 1:
odds.append(i)
print(odds)
# [1, 3, 5, 7, 9]
Η ίδια διαδικασία μπορεί να γίνει με την filter(), αλλά προτιμάται ο συμβολισμός της κατανόησης λίστας για λόγους απλότητας και σαφήνειας.
Συνδυασμός με τριμερείς τελεστές (επεξεργασία τύπου if else)
Στο παραπάνω παράδειγμα, επεξεργάζονται μόνο εκείνα τα στοιχεία που πληρούν τα κριτήρια και εκείνα που δεν πληρούν τα κριτήρια αποκλείονται από τη νέα λίστα.
Αν θέλετε να αλλάξετε τη διαδικασία ανάλογα με τη συνθήκη ή αν θέλετε να επεξεργαστείτε διαφορετικά τα στοιχεία που δεν ικανοποιούν τη συνθήκη, όπως στην περίπτωση if else, χρησιμοποιήστε τον τελεστή ternary.
Στην Python, ο τελεστής ternary μπορεί να γραφτεί ως εξής
Value When True if Conditional Expression else Value When False
Αυτό χρησιμοποιείται στο τμήμα έκφρασης του συμβολισμού κατανόησης λίστας, όπως φαίνεται παρακάτω.
[Value When True if Conditional Expression else Value When False for Any Variable Name in Iterable Object]
Δίνεται ένα παράδειγμα μαζί με μια ισοδύναμη δήλωση for.
odd_even = ['odd' if i % 2 == 1 else 'even' for i in range(10)]
print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
odd_even = []
for i in range(10):
if i % 2 == 1:
odd_even.append('odd')
else:
odd_even.append('even')
print(odd_even)
# ['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
Είναι επίσης δυνατό να γράψετε εκφράσεις χρησιμοποιώντας αυθαίρετα ονόματα μεταβλητών για τις τιμές true και false.
Εάν η συνθήκη ικανοποιείται, γίνεται κάποια επεξεργασία, διαφορετικά η τιμή του αρχικού αντικειμένου iterable παραμένει αμετάβλητη.
odd10 = [i * 10 if i % 2 == 1 else i for i in range(10)]
print(odd10)
# [0, 10, 2, 30, 4, 50, 6, 70, 8, 90]
Συνδυασμός με zip() και enumerate()
Χρήσιμες συναρτήσεις που χρησιμοποιούνται συχνά στην εντολή for είναι η zip(), η οποία συνδυάζει πολλαπλές επαναληπτικές τιμές, και η enumerate(), η οποία επιστρέφει μια τιμή μαζί με το δείκτη της.
Φυσικά, είναι δυνατόν να χρησιμοποιήσετε τις zip() και enumerate() με συμβολισμό κατανόησης λίστας. Δεν πρόκειται για ειδική σύνταξη και δεν είναι δύσκολο αν λάβετε υπόψη σας την αντιστοιχία με την εντολή for.
Παράδειγμα της zip().
l_str1 = ['a', 'b', 'c']
l_str2 = ['x', 'y', 'z']
l_zip = [(s1, s2) for s1, s2 in zip(l_str1, l_str2)]
print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]
l_zip = []
for s1, s2 in zip(l_str1, l_str2):
l_zip.append((s1, s2))
print(l_zip)
# [('a', 'x'), ('b', 'y'), ('c', 'z')]
Παράδειγμα της enumerate().
l_enu = [(i, s) for i, s in enumerate(l_str1)]
print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]
l_enu = []
for i, s in enumerate(l_str1):
l_enu.append((i, s))
print(l_enu)
# [(0, 'a'), (1, 'b'), (2, 'c')]
Η ιδέα είναι η ίδια με την προηγούμενη χρήση του if.
l_zip_if = [(s1, s2) for s1, s2 in zip(l_str1, l_str2) if s1 != 'b']
print(l_zip_if)
# [('a', 'x'), ('c', 'z')]
Κάθε στοιχείο μπορεί επίσης να χρησιμοποιηθεί για τον υπολογισμό ενός νέου στοιχείου.
l_int1 = [1, 2, 3]
l_int2 = [10, 20, 30]
l_sub = [i2 - i1 for i1, i2 in zip(l_int1, l_int2)]
print(l_sub)
# [9, 18, 27]
συμβολισμός συμπερίληψης εμφωλευμένης λίστας
Όπως οι βρόχοι for, έτσι και οι συμβολισμοί κατανόησης λίστας μπορούν επίσης να φωλιαστούν.
[Expression for Variable Name 1 in Iterable Object 1
for Variable Name 2 in Iterable Object 2
for Variable Name 3 in Iterable Object 3 ... ]
Για λόγους ευκολίας, έχουν προστεθεί διαλείψεις και εσοχές, αλλά δεν απαιτούνται για τη γραμματική- μπορούν να συνεχιστούν σε μία μόνο γραμμή.
Δίνεται ένα παράδειγμα μαζί με μια ισοδύναμη δήλωση for.
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [x for row in matrix for x in row]
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
flat = []
for row in matrix:
for x in row:
flat.append(x)
print(flat)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
Είναι επίσης δυνατή η χρήση πολλαπλών μεταβλητών.
cells = [(row, col) for row in range(3) for col in range(2)]
print(cells)
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
Μπορείτε επίσης να κάνετε διακλάδωση υπό όρους.
cells = [(row, col) for row in range(3)
for col in range(2) if col == row]
print(cells)
# [(0, 0), (1, 1)]
Είναι επίσης δυνατή η υπό όρους διακλάδωση για κάθε αντικείμενο επανάληψης.
cells = [(row, col) for row in range(3) if row % 2 == 0
for col in range(2) if col % 2 == 0]
print(cells)
# [(0, 0), (2, 0)]
συμβολισμός συμπερίληψης συνόλου(Set comprehensions)
Η αλλαγή των τετράγωνων αγκυλών [] στον συμβολισμό κατανόησης λίστας σε καμπύλες αγκύλες {} δημιουργεί ένα σύνολο (αντικείμενο τύπου συνόλου).
{Expression for Any Variable Name in Iterable Object}
s = {i**2 for i in range(5)}
print(s)
# {0, 1, 4, 9, 16}
συμβολισμός συμπερίληψης λεξικού(Dict comprehensions)
Τα λεξικά (αντικείμενα τύπου dict) μπορούν επίσης να δημιουργηθούν με τον συμβολισμό κατανόησης.
{}, και καθορίστε το κλειδί και την τιμή στο τμήμα έκφρασης ως κλειδί: τιμή.
{Key: Value for Any Variable Name in Iterable Object}
Οποιαδήποτε έκφραση μπορεί να καθοριστεί για το κλειδί και την τιμή.
l = ['Alice', 'Bob', 'Charlie']
d = {s: len(s) for s in l}
print(d)
# {'Alice': 5, 'Bob': 3, 'Charlie': 7}
Για να δημιουργήσετε ένα νέο λεξικό από μια λίστα κλειδιών και τιμών, χρησιμοποιήστε τη συνάρτηση zip().
keys = ['k1', 'k2', 'k3']
values = [1, 2, 3]
d = {k: v for k, v in zip(keys, values)}
print(d)
# {'k1': 1, 'k2': 2, 'k3': 3}
τύπος γεννήτριας(Generator expressions)
Εάν οι τετράγωνες αγκύλες [] στη σημειογραφία κατανόησης λίστας χρησιμοποιηθούν ως στρογγυλές αγκύλες (), επιστρέφεται μια γεννήτρια αντί για μια πλειάδα. Αυτό ονομάζεται εκφράσεις γεννήτριας.
Παράδειγμα συμβολισμού κατανόησης λίστας.
l = [i**2 for i in range(5)]
print(l)
# [0, 1, 4, 9, 16]
print(type(l))
# <class 'list'>
Παράδειγμα έκφρασης γεννήτριας. Αν εκτυπώσετε() τη γεννήτρια ως έχει, δεν θα εκτυπώσει τα περιεχόμενά της, αλλά αν την εκτελέσετε με μια εντολή for, μπορείτε να λάβετε τα περιεχόμενά της.
g = (i**2 for i in range(5))
print(g)
# <generator object <genexpr> at 0x10af944f8>
print(type(g))
# <class 'generator'>
for i in g:
print(i)
# 0
# 1
# 4
# 9
# 16
Οι εκφράσεις γεννήτριας επιτρέπουν επίσης τη διακλάδωση υπό όρους και τη φωλεοποίηση με τη χρήση της συμβολής if καθώς και της συμβολής κατανόησης λίστας.
g_cells = ((row, col) for row in range(0, 3)
for col in range(0, 2) if col == row)
print(type(g_cells))
# <class 'generator'>
for i in g_cells:
print(i)
# (0, 0)
# (1, 1)
Για παράδειγμα, εάν μια λίστα με μεγάλο αριθμό στοιχείων δημιουργηθεί χρησιμοποιώντας τη σημειογραφία κατανόησης λίστας και στη συνέχεια γίνει επανάληψη με μια εντολή for, η λίστα που περιέχει όλα τα στοιχεία θα δημιουργηθεί στην αρχή εάν χρησιμοποιηθεί η σημειογραφία κατανόησης λίστας. Από την άλλη πλευρά, αν χρησιμοποιήσετε μια έκφραση γεννήτριας, κάθε φορά που επαναλαμβάνεται ο βρόχος, τα στοιχεία παράγονται ένα προς ένα, μειώνοντας έτσι το μέγεθος της μνήμης που χρησιμοποιείται.
Εάν η έκφραση γεννήτριας είναι το μοναδικό όρισμα της συνάρτησης, οι στρογγυλές αγκύλες () μπορούν να παραλειφθούν.
print(sum([i**2 for i in range(5)]))
# 30
print(sum((i**2 for i in range(5))))
# 30
print(sum(i**2 for i in range(5)))
# 30
Όσον αφορά την ταχύτητα επεξεργασίας, ο συμβολισμός κατανόησης λίστας είναι συχνά ταχύτερος από τον συμβολισμό γεννήτριας όταν επεξεργάζονται όλα τα στοιχεία.
Ωστόσο, όταν κρίνετε με all() ή any(), για παράδειγμα, το αποτέλεσμα καθορίζεται όταν υπάρχει false ή true, οπότε η χρήση εκφράσεων γεννήτριας μπορεί να είναι ταχύτερη από τη χρήση συμβολισμού κατανόησης λίστας.
Δεν υπάρχει συμβολισμός κατανόησης πλειάδας, αλλά αν χρησιμοποιήσετε μια έκφραση γεννήτριας ως όρισμα της tuple(), μπορείτε να δημιουργήσετε μια πλειάδα στον συμβολισμό κατανόησης.
t = tuple(i**2 for i in range(5))
print(t)
# (0, 1, 4, 9, 16)
print(type(t))
# <class 'tuple'>