Python Advanced Data Types
Advanced Data Types
This page covers Python advanced data types and continues the previous tutorial of Python data types.
For Python intermediate data types here.
It covers some of the aspects of data types in more details.
- slicing (steps and negative indexing)
- sorting lists (sort vs sorted and reverse sorting)
- copying objects
Slicing
As defined previously, slicing produces partial parts of a data type. In other words, the method cuts data and outputs it.
Here, slicing introduces its third argument, steps. It also covers negative indexing.
Steps
The last argument goes at the end, and it changes the setting of how many steps the slicing takes.
The following are examples of slicing with all arguments.
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] print(a[0:8:2]) Output: [1, 3, 5, 7]
a = "Hi, friend!" print(a[0:11:2]) Output: H,fin!
The process behind the above example. Please note that in slicing, the first item always starts from 0 and the last number item is not included.
Hi, friend! H i , f r i e n d ! 0 1 2 3 4 5 6 7 8 9 10 [0:11:2] 0 = start from 1st item 11 = end with 10th item 2 = produce every 2nd item # Output: H,fin! H i , f r i e n d ! 0 2 4 6 8 10
Negative indexing
In Python, negative indexing refers to negative numbers as arguments inside slicing.
Negative indexing follows the same logic as positive indexing, with the difference of producing the outcome in reverse order.
Below are a few examples of slicing with negative indexing.
a = [1, 2, 3, 4, 5, 6, 7, 8, 9] print(a[-1]) Output: 9
a = [1, 2, 3, 4, 5, 6, 7, 8, 9] print(a[-7:-1:1]) Output: [3, 4, 5, 6, 7, 8]
In negative indexing, “-1” always start from the end and goes backwards in reverse order.
In the above case, the slicing starts from “-7” (number 3) and it ends in “-1” (number 9). End argument does not produce the last number, hence the outcome of 8 (index “-2“). Step argument equals 1, which outputs the default value.
Positive indexing 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 Negative indexing 1 2 3 4 5 6 7 8 9 -9 -8 -7 -6 -5 -4 -3 -2 -1
Sorting lists
There are two ways perform sorting with lists, the functions “sort()” and “sorted()“
The main difference in both methods is the effect of their operation onto the data.
- “sort()” performs sorting directly onto the original data
- “sorted()” creates a new copy of the data and then performs the operation
The other distinction of the two is that “sort()” is a list method, and as such, applies only to lists. On the other hand, “sorted()” can perform on other data types such as dictionaries, sets, strings, and tuples.
This means that with any changes to the original data, the outcome of “sort()” changes accordingly. Whereas with “sorted()”, the outcome does not change even if the original data change.
# List of random letters a = ["f", "c", "h", "k", "a", "e", "c", "s"]
Let’s look at sort().
a.sort() print(a) Output: ['a', 'c', 'c', 'e', 'f', 'h', 'k', 's']
Let’s look at sorted().
b = sorted(a) print(a) Output: ['a', 'c', 'c', 'e', 'f', 'h', 'k', 's']
Adding “x” at the beginning of the list.
a.insert(0, "x") print(a) print(b) Output: ['x', 'a', 'c', 'c', 'e', 'f', 'h', 'k', 's'] Output: ['a', 'c', 'c', 'e', 'f', 'h', 'k', 's']
The outcome changes accordingly, “sort()” acts directly onto the original list. But “sorted()” creates a copy of the sequence, stores it in a different variable, and performs the function onto the copy. And as such, it preserves the data in the original list.
Reverse sorting
In Python, sorting features a reverse option. This means that the data is sorted in reverse order.
Both functions operate in the same manner, using the keyword “reverse” as argument.
The Boolean values of True and False represent on and off, respectively (default value = False).
a = ["f", "c", "h", "k", "a", "e", "c", "s"] a.sort(reverse = True) b = sorted(a, reverse = True) print(a) print(b) Output: ['s', 'k', 'h', 'f', 'e', 'c', 'c', 'a'] Output: ['s', 'k', 'h', 'f', 'e', 'c', 'c', 'a']
Copying objects
In Python, copying objects can occur through referencing, shallow copying or deep copying.
Essentially:
- Referencing does not create another object, but rather only references one variable to another. Any changes to the original variable modifies the copy.
- Shallow copying creates a new object, but references the content of the original copy to the new one. Some changes to the original variable modifies the copy.
- Whereas deep copying, creates a new object and copies all content of the original object to the new one. Any changes to the original variable does not modify the copy.
There are several ways of copying objects. This part covers five different types of copying, assigning new variables, declaring data type, slicing, built-in function “copy()”, and copy module.
- Referencing: assigning a new variable
- Shallow copy: declaring data type, slicing, “copy()”, and copy module
- Deep copy: copy module
Python provides a function “id()“, which returns the identifier of an object. This function can help with the below methods.
Referencing
This method only references (binds together) the object’s content from one variable to another.
Assigning new variables (=)
One of the first and most straightforward copying methods is assigning new variables (with the equal operator “=”).
a = [1, 2, 3] b = a print(a) print(b) Output: [1, 2, 3] Output: [1, 2, 3]
a.append(4) print(a) print(b) Output: [1, 2, 3, 4] Output: [1, 2, 3, 4]
Checking the objects’ ids (numbers may differ for each user).
print(id(a)) print(id(b)) # same object id Output: 1336728597056 Output: 1336728597056
Shallow copying
This methods creates a separate object, but references the content of the original to the new copy. Changes in the original object do not modify the new copy.
The exception is with nested objects (such as a list inside another list). In such cases, changes to the original objects modifies the copy, but only the values of the nested objects (see below).
Declaring data types
This method operates similarly to the assigning new variables (referencing), but it declares the data type – e.g. “list()”, “dict()”, etc.
a = [1, 2, 3] b = list(a) print(a) print(b) Output: [1, 2, 3] Output: [1, 2, 3]
a.append(4) print(a) print(b) Output: [1, 2, 3, 4] Output: [1, 2, 3]
print(id(a)) print(id(b)) # different object ids Output: 2189100364352 Output: 2189100347456
Slicing
Another method for shallow copying is slicing.
a = [1, 2, 3] b = a[:] print(a) print(b) # Output: [1, 2, 3] # Output: [1, 2, 3]
a.append(4) print(a) print(b) # Output: [1, 2, 3, 4] # Output: [1, 2, 3]
print(id(a)) print(id(b)) # different object ids # Output: 2121497424448 # Output: 2121497407360
Built-in function copy()
In Python, data types have a built-in function “copy()”, another shallow copying method.
a = [1, 2, 3] b = a.copy() print(a) print(b) # Output: [1, 2, 3] # Output: [1, 2, 3]
a.append(4) print(a) print(b) # Output: [1, 2, 3, 4] # Output: [1, 2, 3]
print(id(a)) print(id(b)) # different object ids # Output: 3197883101760 # Output: 3197883084672
copy module
The copy module offers both shallow and deep copying. This part covers the shallow copy.
import copy a = [1, 2, 3] b = copy.copy(a) print(a) print(b) # Output: [1, 2, 3] # Output: [1, 2, 3]
a.append(4) print(a) print(b) # Output: [1, 2, 3, 4] # Output: [1, 2, 3]
print(id(a)) print(id(b)) # different object ids # Output: 2391954761472 # Output: 2391954761408
Nested objects
As mentioned above, shallow copying changes to the copied object’s content in the case of nested objects.
This part covers the built-in function “copy()”, but it applies to all shallow copy methods.
a = [1, 2, 3, [4, 5]] b = a.copy() print(a) print(b) # Output: [1, 2, 3, [4, 5]] # Output: [1, 2, 3, [4, 5]]
Changing some values inside the original object as well as its nested object (second list).
a[0] = 33 a[3][0] = 15 print(a) print(b) # Output: [33, 2, 3, [15, 5]] # Output: [1, 2, 3, [15, 5]]
The changes in the copied object (b) reflect the changes of the original object (a) only on the nested object (2nd list).
Deep copying
The method of deep copying creates a new object as well as all content (also nested objects) from the original to the new copy.
In Python, this is possible through the built-in module copy.
module copy
This part covers deep copying method from the copy module.
import copy a = [1, 2, 3, [4, 5]] b = copy.deepcopy(a) print(a) print(b) # Output: [1, 2, 3, [4, 5]] # Output: [1, 2, 3, [4, 5]]
a[0] = 33 a[3][0] = 15 print(a) print(b) # Output: [33, 2, 3, [15, 5]] # Output: [1, 2, 3, [4, 5]]
Changing some of the values in the original list (a).
a[0] = 33 a[3][0] = 15 print(a) print(b) # Output: [33, 2, 3, [15, 5]] # Output: [1, 2, 3, [4, 5]]
Modifications in the original list do not reflect in the copy.
print(id(a)) print(id(b)) # Output: 2472779327168 # Output: 2472783895424