Od czasów Pythona 1.4 składnia wykrojeń pozwalała na użycie trzeciego
argumentu, oznaczającego "krok". Wszystkie następujące napisy
są więc zgodne ze składnią Pythona: L[1:10:2], L[:-1:1],
L[::-1]. Własność ta została dodana na prośbę autorów pracujących
nad projektem Numerical Python, w którym trzeci argument jest wykorzystywany
bardzo intensywnie. Dotychczas jednak, choć składnia
dopuszczała użycie rozszerzonego zapisu, wbudowane typy sekwencyjne, takie
jak listy, krotki, czy napisy, nigdy z niego nie korzystały (przy użyciu
rozszerzonego wykrojenia generowany był wyjątek TypeError.
Dzięki łatce Michaela Hudsona w Pythonie 2.3 niedociągnięcie to zostało
poprawione.
Możemy teraz na przykład wybrać z listy wszystkie elementy o parzystych indeksach:
>>> L = range(10) >>> L[::2] [0, 2, 4, 6, 8]
Wartości ujemne są również dopuszczalne, pozwalając na utworzenie kopii listy w odwrotnym porządku:
>>> L[::-1] [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Podobnie rzecz się ma z krotkami, tablicami i napisami:
>>> s='abcd' >>> s[::2] 'ac' >>> s[::-1] 'dcba'
Operując na sekwencjach zmiennych (tj. na listach lub tablicach), możemy używać rozszerzonych wykrojeń w części docelowej instrukcji przypisania lub usunięcia, jednak pomiędzy przypisaniami do zwykłych i rozszerzonych wykrojeń występują pewne różnice. Wykonując przypisanie do zwykłego wykrojenia możemy zmienić długość sekwencji:
>>> a = range(3) >>> a [0, 1, 2] >>> a[1:3] = [4, 5, 6] >>> a [0, 4, 5, 6]
Elastyczność rozszerzonych wykrojeń jest jednak ograniczona -- jeśli przy przypisaniu do rozszerzonego wykrojenia po prawej stronie znaku równości występuje lista, to musi ona zawierać tę samą liczbę elementów, co samo wykrojenie:
>>> a = range(4) >>> a [0, 1, 2, 3] >>> a[::2] [0, 2] >>> a[::2] = [0, -1] >>> a [0, 1, -1, 3] >>> a[::2] = [0,1,2] Traceback (most recent call last): File "<stdin>", line 1, in ? ValueError: attempt to assign sequence of size 3 to extended slice of size 2
Usuwanie działa w bardziej oczywisty sposób:
>>> a = range(4) >>> a [0, 1, 2, 3] >>> a[::2] [0, 2] >>> del a[::2] >>> a [1, 3]
Można również przekazywać obiekty wykrojenia metodzie __getitem__ wbudowanych typów sekwencyjnych:
>>> range(10).__getitem__(slice(0, 5, 2)) [0, 2, 4]
lub też używać obiektów wykrojenia bezpośrednio w odwołaniach do indeksów:
>>> range(10)[slice(0, 5, 2)] [0, 2, 4]
Aby ułatwić implementowanie sekwencji, które obsługują rozszerzone
wykrojenia, do obiektów wykrojenia dodano metodę indices(długość), która
po podaniu długości sekwencji zwraca krotkę (początek, koniec, krok),
którą można przekazać bezpośrednio do funkcji range().
Metoda indices() obsługuje indeksy pominięte lub wykraczające poza
dopuszczalny zakres w sposób zgodny ze zwykłymi wykrojeniami (a stwierdzenie to kryje
w sobie szereg nieciekawych szczegółów). Metody należy używać w następujący
sposób:
class UdawanaSekw:
...
def oblicz_element(self, i):
...
def __getitem__(self, element):
if isinstance(element, slice):
indeksy = element.indices(len(self))
return UdawanaSekw([self.oblicz_element(i) for i in range(*indeksy)])
else:
return self.oblicz_element(i)
W przykładzie widać też, że wbudowany obiekt slice jest teraz obiektem typu wykrojeniowego, a nie funkcją. Jest to zgodne z duchem zmian wprowadzonych w Pythonie 2.2, w którym typami stały się int, str.
Zajrzyj do Informacji na temat tej publikacji... aby pomóc w jej rozwoju.