# understanding of python slice notation

Lets start with understanding of python slice notation. We can access element in python lists/iterables by indexing. Slicing in python lists is defined as taking a part of the list from a bigger list. In python slicing takes 3 arguments 1. start index, 2. end index, 3. step to skip number of indexes. when we take slice in list it will create a new list/new iterable, starts from the given index and adds the element to the new list/new iterable. After it increments the index by step value and then adds the element to the new list/iterable until the incremented index is less than the end index. The basic form of the slice notation is [start:end:step] default values of the slice notation is [None:None:None]. valid values for start, end, step are non zero integers or None type only. We have a builtin function "slice". It takes parameters as start index, end index  and step and returns a slice object.

• If start is not given or "None" then the value of start is 0
• If end is not given or "None" then the value of end is length of the list/iterable type.
• If step is "None" it then value of step is 1.
• when we use a slice notation it will create a new iterable object of given type.

## Basic usage of slice function in python

```# using python slice function
my_tuple = (1,2,3,4,5,6,7,9)
slice_obj = slice(1:6:2)
my_slice = my_tuple[slice_obj]
print(my_slice)
# Output: (2, 4, 6)```

In above code, the slice function taken start index as 1, end index as 6, step as 2 and returned the slice obect. The returned slice object is  used with variable "my_tuple" and returned the sliced tuple (2, 4, 6).

## Usage of step in slice notation

```numbers = [1,2,3,4,5,6,7,8,9,10]
even_nums = numbers[1:8:2]
print(even_nums)
# Output: [2, 4, 6, 8]
```

In above code, the slice notation start index is 1 and end index is 8 and step is 2. It will generate the index values which are between 1(inclusive) and 8(exclusive) those are 1, 3, 5 and 7. and the values are  numbers  is 2, numbers is 4, numbers is 6 and numbers  is 8. So, we get the output as [2, 4, 6, 8].

## Copy a list using slice notation

```my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
copied_list = my_list[:]
# equivalent code to above statement
copied_list = my_list[None:None:None]
print(id(my_list), id(copied_list))
# Output: 140557707995328, 140557707995400
my_tuple = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
copied_tuple = my_tuple[:]
print(id(my_tuple), id(copied_tuple))
# Output: 140557707834512, 140557707834512
```

In above code, we have not specified start index, end index and step. So, it will takes start index value as 0, end index value as max of length of iterable type( in our case it's 10) and step as 1. So, It will generate all the index values starting from zero to nine. Which will result in all the elements in the list. We use python's built-in function "id" to check the memory location. We can see in above code that the orizinal list and copied list both have different values of memory locations. So, We can copy the list using python's slice notation.

Note: we cannot copy the tuple/string(immutable datatype) with slice notation.

## Replacing data in list(mutable objects) with slice notation

```my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
my_list[1:7:2] = ["hi", "hello", "hey"]
print(my_list)
# Output: [0, 'hi', 2, 'hello', 4, 'hey', 6, 7, 8, 9]
```

## Remove data in list(mutable objects) with slice notation

```my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
my_list[1:7] = []
print(my_list)
# Output: [0, 7, 8, 9]```

But, It will not work with step value of absolute(- or +) greater than 1 will not work.

## Reverse the data with python slice notation

```my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
new_list = my_list[::-1]
print(new_list)
# Output: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]```

Note: We can use slicing on all python sequence data types

• strings.
• byte sequences.
• byte arrays.
• lists.
• tuples.
• range objects.

Reference:

``` 