Μια list είναι μια τροποποιήσιμη συλλογή στοιχείων σε σειρά. Όπως οι περισσότερες συλλογές (δες τα ενσωματωμένα tuple, dict και set), οι λίστες μπορούν να κρατούν αναφορές σε οποιονδήποτε (ή σε πολλαπλούς) τύπο δεδομένων, ακόμη και σε άλλες λίστες. Στην Python θεωρούνται τύπος ακολουθίας και μπορούν να αντιγραφούν ολόκληρες ή εν μέρει μέσω συμβολισμού τομής.
Όπως κάθε ακολουθία, τα στοιχεία μέσα στις lists μπορούν να αναφερθούν με αριθμό 0-based index από τα αριστερά ή με αριθμό -1-based index από τα δεξιά.
Οι λίστες υποστηρίζουν και συνήθεις πράξεις ακολουθιών και πράξεις τροποποιήσιμων ακολουθιών, όπως min(<list>)/max(<list>), <list>.index(), <list>.append() και <list>.reverse().
Τα στοιχεία μπορούν να διατρεχθούν με τη δομή for item in <list>, και με τη δομή for index, item in enumerate(<list>) όταν χρειάζεσαι και το στοιχείο και τη θέση του.
Η Python παρέχει πολλές χρήσιμες μεθόδους για να δουλεύεις με λίστες.
Επειδή οι λίστες είναι τροποποιήσιμες, οι μέθοδοι των λιστών τροποποιούν το αρχικό αντικείμενο λίστας που περνάς στη μέθοδο.
Αν δεν θέλεις να τροποποιηθεί, χρειάζεται να κάνεις ένα shallow copy (τουλάχιστον) της αρχικής list μέσω slice ή <list>.copy().
Μπορείς να προσθέσεις στοιχεία στο τέλος μιας υπάρχουσας λίστας με τη <list>.append(<item>):
>>> numbers = [1, 2, 3]
>>> numbers.append(9)
>>> numbers
[1, 2, 3, 9]
Αντί να κάνεις append, η <list>.insert(<index>, <item>) προσθέτει το στοιχείο σε συγκεκριμένη θέση μέσα στη λίστα.
Το <index> είναι η θέση του στοιχείου πριν από το οποίο θέλεις να εμφανιστεί το νέο στοιχείο.
Το <item> είναι το στοιχείο που θα εισαχθεί.
Σημείωση: Αν το <index> είναι 0, το στοιχείο θα προστεθεί στην αρχή της λίστας.
Αν το <index> είναι μεγαλύτερο από την τελευταία θέση της λίστας, το στοιχείο θα προστεθεί στην τελευταία θέση, δηλαδή το ίδιο με το να χρησιμοποιήσεις <list>.append(<item>).
>>> numbers = [1, 2, 3]
>>> numbers.insert(0, -2)
>>> numbers
[-2, 1, 2, 3]
>>> numbers.insert(1, 0)
>>> numbers
[-2, 0, 1, 2, 3]
Ένα iterable μπορεί να συνδυαστεί με μια υπάρχουσα λίστα (συνένωση των δύο) μέσω <list>.extend(<iterable>).
Η <list>.extend(<iterable>) θα ξεδιπλώσει το iterable που δίνεις, προσθέτοντας τα στοιχεία του με την ίδια σειρά στο τέλος της λίστας-στόχου.
Αν χρησιμοποιήσεις <list>.append(<item>) σε αυτή την περίπτωση, θα προσθέσεις ολόκληρο το iterable ως ένα μόνο στοιχείο.
>>> numbers = [1, 2, 3]
>>> other_numbers = [5, 6, 7]
>>> numbers.extend(other_numbers)
>>> numbers
[1, 2, 3, 5, 6, 7]
>>> numbers.extend([8, 9])
>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9]
Μπορείς να χρησιμοποιήσεις τη <list>.remove(<item>) για να αφαιρέσεις ένα στοιχείο από τη λίστα.
Η <list>.remove(<item>) θα πετάξει ένα ValueError αν το στοιχείο δεν υπάρχει στη λίστα.
>>> numbers = [1, 2, 3]
>>> numbers.remove(2)
>>> numbers
[1, 3]
# Trying to remove a value that is not in the list throws a ValueError.
>>> numbers.remove(0)
ValueError: list.remove(x): x not in list
Εναλλακτικά, με τη μέθοδο <list>.pop(<index>) και αφαιρείς και κάνεις return σε ένα στοιχείο για να το χρησιμοποιήσεις.
Η <list>.pop(<index>) παίρνει μία προαιρετική παράμετρο: το index του στοιχείου που θα αφαιρεθεί και θα επιστραφεί.
Αν δεν ορίσεις το προαιρετικό όρισμα <index>, θα αφαιρεθεί και θα επιστραφεί το τελευταίο στοιχείο της λίστας.
Αν το <index> είναι μεγαλύτερος αριθμός από την τελευταία θέση της λίστας, η μέθοδος θα πετάξει ένα IndexError.
>>> numbers = [1, 2, 3]
>>> numbers.pop(0)
1
>>> numbers
[2, 3]
>>> numbers.pop()
3
>>> numbers
[2]
# This will throw an error because there is only index 0.
>>> numbers.pop(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop index out of range
Μπορείς να αφαιρέσεις όλα τα στοιχεία από μια list με τη <list>.clear(). Δεν παίρνει καμία παράμετρο.
>>> numbers = [1, 2, 3]
>>> numbers.clear()
>>> numbers
[]
Η σειρά των στοιχείων μιας λίστας μπορεί να αντιστραφεί επί τόπου με τη <list>.reverse(). Αυτό τροποποιεί την αρχική λίστα.
>>> numbers = [1, 2, 3]
>>> numbers.reverse()
>>> numbers
[3, 2, 1]
Μια λίστα μπορεί να αναδιαταχθεί επί τόπου με τη βοήθεια της <list>.sort().
Η προεπιλεγμένη σειρά ταξινόμησης είναι αύξουσα από τα αριστερά.
Η τεκμηρίωση της Python προσφέρει πρόσθετες συμβουλές και τεχνικές για ταξινόμηση.
Από το 2002 έως το 2022, η Python χρησιμοποιούσε εσωτερικά έναν αλγόριθμο με το όνομα Timsort για να τακτοποιεί τις λίστες, αλλά από την Python 3.11 και μετά πέρασε στον Powersort.
Μπορείς να διαβάσεις περισσότερες λεπτομέρειες και τη σχετική συζήτηση της βασικής ομάδας της Python στο GitHub, στο ζήτημα 78742.
Για τεχνικές λεπτομέρειες του αλγορίθμου, δες την εργασία των J. Ian Munro και Sebastian Wild Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally Adapt to Existing Runs
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
# The default sort order is *ascending*.
>>> names.sort()
>>> names
["Bruce", "Natasha", "Thor", "Tony"]
Για να ταξινομήσεις μια λίστα σε φθίνουσα σειρά, δώσε το όρισμα reverse=True στη μέθοδο:
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
>>> names.sort(reverse=True)
>>> names
["Tony", "Thor", "Natasha", "Bruce"]
Στις περιπτώσεις που δεν θέλεις να τροποποιηθεί η αρχική list, μπορείς να χρησιμοποιήσεις τις ενσωματωμένες συναρτήσεις sorted() και reversed().
Η sorted(<list>) θα επιστρέψει ένα ταξινομημένο αντίγραφο και παίρνει τις ίδιες παραμέτρους με τη <list>.sort().
Η reversed(<list>) επιστρέφει έναν επαναλήπτη που δίνει τα στοιχεία της λίστας σε αντίστροφη σειρά.
Τα Iterators θα καλυφθούν αναλυτικά σε άλλη άσκηση.
Μπορείς να βρεις πόσες φορές εμφανίζεται ένα στοιχείο σε μια λίστα με τη βοήθεια της <list>.count(<item>).
Επιστρέφει τον συνολικό αριθμό των φορών που το <item> εμφανίζεται ως στοιχείο της λίστας.
>>> items = [1, 4, 7, 8, 2, 9, 2, 1, 1, 0, 4, 3]
>>> items.count(1)
3
Η <list>.index(<item>) θα επιστρέψει τη θέση της πρώτης εμφάνισης του στοιχείου που δίνεις.
Αν δεν υπάρχει καμία εμφάνιση, η μέθοδος πετάει ένα ValueError.
Η αρίθμηση γίνεται με 0-based από τα αριστερά, που σημαίνει ότι η θέση του πρώτου στοιχείου είναι 0.
Υποστηρίζεται και αρίθμηση από τα δεξιά, ξεκινώντας από τη θέση -1.
>>> items = [7, 4, 1, 0, 2, 5]
>>> items.index(4)
1
>>> items.index(10)
ValueError: 10 is not in list
Αν δώσεις τις θέσεις start και end, η αναζήτηση θα γίνει σε ένα συγκεκριμένο τμήμα της λίστας:
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> names.index("Tina")
0
>>> names.index("Tina", 2, 5)
3
Αν δεν χρειάζεσαι την ακριβή θέση ενός στοιχείου, ο ενσωματωμένος τελεστής in είναι πιο αποδοτικός για να ελέγξεις αν υπάρχει.
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> "Thomas" in names
True
Θυμήσου ότι οι μεταβλητές στην Python είναι ονόματα που δείχνουν σε υποκείμενα αντικείμενα.
Τα ονόματα μπορούν να δεθούν ή να ξαναδεθούν σε διαφορετικά αντικείμενα κατά τη διάρκεια ζωής ενός προγράμματος.
Η ανάθεση ενός αντικειμένου list σε ένα νέο όνομα μεταβλητής δεν αντιγράφει το αντικείμενο ούτε κανένα από τα δεδομένα στα οποία αναφέρεται.
Το νέο όνομα και το παλιό όνομα θα δείχνουν και τα δύο στο ίδιο αντικείμενο list.
Επιπλέον, οι λίστες είναι αντικείμενα τύπου περιέκτη: για να εξοικονομείται χώρος, οι περιέκτες κρατούν μόνο αναφορές στα στοιχεία τους, όχι τα ίδια τα στοιχεία.
Αυτή η "βελτιστοποίηση" μπορεί να έχει απρόβλεπτες συνέπειες για όποιον δεν το προσέχει.
Η <list>.copy() θα δημιουργήσει ένα νέο αντικείμενο list, αλλά δεν θα δημιουργήσει νέα αντικείμενα για τα στοιχεία της λίστας στα οποία αναφέρεται: το αντίγραφο είναι "ρηχό".
Μια shallow copy αρκεί συνήθως όταν θέλεις να προσθέσεις ή να αφαιρέσεις στοιχεία από το ένα αντικείμενο list χωρίς να τροποποιήσεις το άλλο.
Αν όμως υπάρχει οποιαδήποτε πιθανότητα να τροποποιηθούν κατά λάθος τα υποκείμενα στοιχεία μιας list (και μαζί τους όλα τα σχετικά ρηχά αντίγραφα), θα πρέπει να χρησιμοποιήσεις τη copy.deepcopy() από το module copy για να δημιουργήσεις ένα πλήρες ή "βαθύ" αντίγραφο όλων των αναφορών και των αντικειμένων.
Για μια αναλυτική εξήγηση της συμπεριφοράς των ονομάτων, των τιμών, των λιστών και των εμφωλευμένων λιστών, ρίξε μια ματιά σε αυτό το εξαιρετικό άρθρο ιστολογίου του Ned Batchelder: Names and values: making a game board. Το Shallow vs Deep Copying of Python Objects προσφέρει επίσης μια καλή σύνοψη των ζητημάτων που αφορούν τα αντίγραφα.