whatshisface
whatshisface

Reputation: 89

Python3 list slice: specific use in class method

I've seen plenty of Python list slice questions here, I don't believe I'm duplicating anything despite it touching on many of those same questions. My question relates to shortening a list using slices, to create a new list and to update the original list.

My task would be to define a Class method which accepts two arguments (word_list, num) and manipulate word_list using slicing. I keep slicing until word_list is empty, storing each slice in a new list. It's not important which end I slice from in terms of the contents of the slice but simply that I can keep slicing and maintain an accurate record of events.

Take the following:

word_list = ["once", "upon", "a", "time", "there", "lived", "an", "old", "man"]

sub_list1 = word_list[:2] # ["once", "upon"]
word_list = word_list[2:] # ["a", "time", "there", "lived", "an", "old", "man"]

compare this with

word_list = ["once", "upon", "a", "time", "there", "lived", "an", "old", "man"]

sub_list2 = word_list[-2:] # ["old", "man"]
word_list = word_list[:-2] # ["once", "upon", "a", "time", "there", "lived"]

In the first example above the list elements get "shunted down" as the slices are taken, as opposed to the second wherein the list simply gets shorter and nothing "moves". Am I inventing a problem or are there any actual implications in slicing word_list differently?

Upvotes: 1

Views: 233

Answers (2)

kederrac
kederrac

Reputation: 17322

not sure if I understand your issue, but I can't see any actual implications between your first and second example, it is just your interpretation

you can have a look over the performance whitch is the same:

import numpy as np
import struct
import sys

from simple_benchmark import BenchmarkBuilder
b = BenchmarkBuilder()

@b.add_function()
def positive_slicing(my_list):
    sub_list = my_list[:2]
    my_list = my_list[2:]

@b.add_function()
def negative_slicing(my_list):
    sub_list = my_list[-2:]
    my_list = my_list[:-2]

@b.add_arguments('slicing list')
def argument_provider():
    for exp in range(2, 7):
        size = 10**exp
        yield size, ['some random example'] * size

r = b.run()
r.plot()

enter image description here

Upvotes: 1

chepner
chepner

Reputation: 531045

Extended slice syntax works by creating a slice object to pass to the appropriate __getitem__ method. foo[x:y:z] becomes foo.__getitem__(slice(x, y, z)).

No assumptions are made about missing values; the value None is simply passed along to slice. So your expressions become

word_list[:2]   -> word_list.__getitem__(slice(None, 2, None))
word_list[2:]   -> word_list.__getitem__(slice(2, None, None))
word_list[:-2]   -> word_list.__getitem__(slice(None, -2, None))
word_list[-2:]   -> word_list.__getitem__(slice(-2, None, None))

It is up to the implementation of __getitem__ to decide how to treat each None value. Typically, context is taken into account. If the step is positive, a missing start is treated as 0; if it's negative, as -1. A missing step usually defaults to 1, regardless of the start and stop positions; that's why something like foo[10:0] is empty rather than assuming you want to use a step of -1.

Upvotes: 2

Related Questions