Χρειάζομαι μια καλή εξήγηση (οι αναφορές είναι ένα συν) σχετικά με τη σημειογραφία φέτα της Python's.
Για μένα, αυτός ο συμβολισμός χρειάζεται λίγο μάζεμα.
Φαίνεται εξαιρετικά ισχυρή, αλλά δεν την έχω καταλάβει.
Είναι πραγματικά πολύ απλό:
a[start:stop] # items start through stop-1
a[start:] # items start through the rest of the array
a[:stop] # items from the beginning through stop-1
a[:] # a copy of the whole array
Υπάρχει επίσης η τιμή step
, η οποία μπορεί να χρησιμοποιηθεί με οποιοδήποτε από τα παραπάνω:
a[start:stop:step] # start through not past stop, by step
Το βασικό σημείο που πρέπει να θυμάστε είναι ότι η τιμή :stop
αντιπροσωπεύει την πρώτη τιμή που δεν βρίσκεται στην επιλεγμένη φέτα. Έτσι, η διαφορά μεταξύ stop
και start
είναι ο αριθμός των στοιχείων που επιλέγονται (αν το step
είναι 1, η προεπιλογή).
Το άλλο χαρακτηριστικό είναι ότι το start
ή το stop
μπορεί να είναι ένας αρνητικός αριθμός, που σημαίνει ότι μετράει από το τέλος του πίνακα αντί για την αρχή. Έτσι:
a[-1] # last item in the array
a[-2:] # last two items in the array
a[:-2] # everything except the last two items
Ομοίως, το step
μπορεί να είναι αρνητικός αριθμός:
a[::-1] # all items in the array, reversed
a[1::-1] # the first two items, reversed
a[:-3:-1] # the last two items, reversed
a[-3::-1] # everything except the last two items, reversed
Η Python είναι ευγενική με τον προγραμματιστή αν υπάρχουν λιγότερα στοιχεία από αυτά που ζητάτε. Για παράδειγμα, αν ζητήσετε a[:-2]
και το a
περιέχει μόνο ένα στοιχείο, θα πάρετε μια κενή λίστα αντί για σφάλμα. Μερικές φορές θα προτιμούσατε το σφάλμα, οπότε πρέπει να γνωρίζετε ότι αυτό μπορεί να συμβεί.
slice()
Ο τελεστής τεμαχισμού []
στην πραγματικότητα χρησιμοποιείται στον παραπάνω κώδικα με ένα αντικείμενο slice()
χρησιμοποιώντας τον συμβολισμό :
(ο οποίος είναι έγκυρος μόνο μέσα στο []
), δηλ:
a[start:stop:step]
ισοδυναμεί με:
a[slice(start, stop, step)]
Τα αντικείμενα Slice συμπεριφέρονται επίσης ελαφρώς διαφορετικά ανάλογα με τον αριθμό των ορίων, παρόμοια με την range()
, δηλαδή υποστηρίζονται τόσο η slice(stop)
όσο και η slice(start, stop[, step])
.
Για να παραλείψετε τον προσδιορισμό ενός συγκεκριμένου ορίσματος, θα μπορούσατε να χρησιμοποιήσετε το None
, έτσι ώστε π.χ. το a[start:]
να είναι ισοδύναμο με το a[slice(start, None)]
ή το a[::-1]
να είναι ισοδύναμο με το a[slice(None, None, -1)]
.
Ενώ η σημειογραφία με βάση το :
είναι πολύ χρήσιμη για απλές φέτες, η ρητή χρήση αντικειμένων slice()
απλοποιεί την προγραμματιστική παραγωγή φέτες.
Το σεμινάριο Python μιλάει γι' αυτό (μετακινηθείτε λίγο προς τα κάτω μέχρι να φτάσετε στο σημείο που αναφέρεται στο slicing).
Το διάγραμμα ASCII art είναι επίσης χρήσιμο για να θυμάστε πώς λειτουργούν οι φέτες:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
Ένας τρόπος για να θυμάστε πώς λειτουργούν οι φέτες είναι να σκεφτείτε ότι οι δείκτες δείχνουν μεταξύ χαρακτήρων, με το αριστερό άκρο του πρώτου χαρακτήρα να έχει τον αριθμό 0. Στη συνέχεια, το δεξί άκρο του τελευταίου χαρακτήρα μιας συμβολοσειράς n χαρακτήρων έχει δείκτη n.
Απαρίθμηση των δυνατοτήτων που επιτρέπει η γραμματική:
>>> seq[:] # [seq[0], seq[1], ..., seq[-1] ]
>>> seq[low:] # [seq[low], seq[low+1], ..., seq[-1] ]
>>> seq[:high] # [seq[0], seq[1], ..., seq[high-1]]
>>> seq[low:high] # [seq[low], seq[low+1], ..., seq[high-1]]
>>> seq[::stride] # [seq[0], seq[stride], ..., seq[-1] ]
>>> seq[low::stride] # [seq[low], seq[low+stride], ..., seq[-1] ]
>>> seq[:high:stride] # [seq[0], seq[stride], ..., seq[high-1]]
>>> seq[low:high:stride] # [seq[low], seq[low+stride], ..., seq[high-1]]
Φυσικά, αν (high-low)%stride != 0
, τότε το τελικό σημείο θα είναι λίγο πιο χαμηλά από το high-1
.
Αν το stride
είναι αρνητικό, η σειρά αλλάζει λίγο, αφού μετράμε προς τα κάτω:
>>> seq[::-stride] # [seq[-1], seq[-1-stride], ..., seq[0] ]
>>> seq[high::-stride] # [seq[high], seq[high-stride], ..., seq[0] ]
>>> seq[:low:-stride] # [seq[-1], seq[-1-stride], ..., seq[low+1]]
>>> seq[high:low:-stride] # [seq[high], seq[high-stride], ..., seq[low+1]]
Οι εκτεταμένες τεμαχισμοί (με κόμματα και ελλείψεις) χρησιμοποιούνται κυρίως μόνο από ειδικές δομές δεδομένων (όπως η NumPy)- οι βασικές ακολουθίες δεν τις υποστηρίζουν.
>>> class slicee:
... def __getitem__(self, item):
... return repr(item)
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'