The following modules deal with classes that are not considered as basic, but because of their extreme importance and often usage it would be nice to take a look at them:
Module collections
Module array
Module bytearray
Module enum
collections
namedtuple
Named tuples assign meaning to each position in a tuple and allow for more readable, self-documenting code. They can be used wherever regular tuples are used, and they add the ability to access fields by name instead of position index.
Usual approach:
🪄 Code:
student = ("John","Jakeson",23,"18 B")print(f'Student {student[1]} from group {student[3]} is {student[2]} year old')
📟 Output:
Student Jakeson from group 18 B is 23 year old
To avoid the mess of various indexes we can add some light "OOP-flavor" to this use-case via namedtuple:
🪄 Code:
from collections import namedtupleStudent =namedtuple("Student", "name surname age group")student =Student("John", "Jakeson", 23, "18 B")print(f'Student {student.name}{student.surname} from group {student.group} is {student.age} year old')print(student)
📟 Output:
Student John Jakeson from group 18 B is 23 year old
Student(name='John', surname='Jakeson', age=23, group='18 B')
Returns a new deque object initialized left-to-right (using append()) with data from iterable. If iterable is not specified, the new deque is empty.
While regular list is efficiently performant only when accessing it's "right side" (via append, extend, pop methods) deque (double edged queue) is efficient from left and right ends both by adding appendleft, extendleft and popleft methods.
🪄 Code:
from collections import dequede =deque("abcde")print(de.pop())print(de.popleft())
If default_factory is not None, it is called without arguments to provide a default value for the given key, this value is inserted in the dictionary for the key, and returned.
🪄 Code:
# Groupping stuff:encountered_animals = [("birds","eagle"), ("mammals","hippo"), ("mammals","panther"), ("snakes","python"), ("birds","hawk"), ("snakes","anaconda")]from collections import defaultdictdeff(animals): spotted_by_group = defaultdict(list) # here list is default_factory which will be called when key will not be found
for type_, animal in animals: spotted_by_group[type_].append(animal)return spotted_by_groupprint(f(encountered_animals))%timeit f(encountered_animals)
This module defines an object type which can compactly represent an array of basic values: characters, integers, floating point numbers.
Arrays are sequence types and behave very much like lists, except that the type of objects stored in them is constrained. The main idea is to give similar API but much less memory footprint if we need a collection of object of the same type. array will consume about sizeof(one object) * len(array) bytes.
The type is specified at object creation time by using a type code, which is a single character. The few of defined type codes (see more in official docs):
Syntax for creating an array:
array.array(typecode[, initializer])
Array has the similar to list operations like indexing and slicing. Also, array has these methods that are the same as in list:
append
extend
count
pop
remove
reverse
index
Some examples:
🪄 Code:
import arraya = array.array('f', [1.2, 2.1])print(f'Array now is {a}, item size is {a.itemsize})')a.append(3.141516925)print(f'After appending array is {a}')# Emulating bytearray type:bytes_array = array.array('b', b"ABC")print(bytes_array)bytes_array.frombytes(b"123")print(bytes_array)
📟 Output:
Array now is array('f', [1.2000000476837158, 2.0999999046325684]), item size is 4)
After appending array is array('f', [1.2000000476837158, 2.0999999046325684, 3.141516923904419])
array('b', [65, 66, 67])
array('b', [65, 66, 67, 49, 50, 51])
numpy
As we can see array is memory-optimized version of a list class. It doesn't have any additional methods for "mathematical"-related operations like matrix transpose, transformation, mutation, filtering and other. In case of those kinds of operations are needed - it is recommended to use powerful and famous module numpy that has many features like:
a powerful N-dimensional array object
sophisticated (broadcasting) functions
tools for integrating C/C++ and Fortran code
useful linear algebra, Fourier transform, and random number capabilities
To install it - either run pip install numpy or use Anaconda distro.
NumPy's main object is the homogeneous multidimensional array. It is a table of elements (usually numbers), all of the same type, indexed by a tuple of non-negative integers. In NumPy dimensions are called axes.
🪄 Code:
import numpy as npa = np.array([2,3,4])print(f'a is {a}, type is {a.dtype}, len is {len(a)}, shape is {a.shape}')b = np.array([(1,2,3), (4,5,6)])print(f'b:\n{b}, shape is {b.shape}')print(f"Transpose T:\n{b.T}")
📟 Output:
a is [2 3 4], type is int64, len is 3, shape is (3,)
b:
[[1 2 3]
[4 5 6]], shape is (2, 3)
Transpose T:
[[1 4]
[2 5]
[3 6]]
🪄 Code:
print("Transforming, add 0.5:\n", b +.5)print("Transforming, add 3*b:\n", b +3*b)print("Transforming, mult by 3:\n", b *3)print("Changing shape:\n", b.reshape(1, 6))
In Python 3 string is a sequence of Unicode characters. If we encode them we will get so-called bytes object suitable for sending over internet or writing it to a socket or file (but usually python hides this from programmer when dealing with files using default encoding). bytes is analogue of the strings used in Python 2. bytes object is immutable, just like regular string and has the same methods.
Good news: due to Python's duck-typing, methods of str, bytes and bytearray are the same, the main difference is that they return the object of the correspondent type. Also, when iterating through bytearray, it will yield bytecode of the character. This can sometimes overcomplicate things.
🪄 Code:
print(b)print(b.lower().startswith(b'hello'))for i in b[:5:-1]:print(i)print()print(b''.join([chr(x).encode('utf8') for x inreversed(b[:5:-1])]))
An enumeration is a set of symbolic names (members) bound to unique, constant values. Within an enumeration, the members can be compared by identity, and the enumeration itself can be iterated over.
In a simplified sense, this is an iteratable set of constants.
from enum import EnumclassColor(Enum): RED =1 GREEN =2 BLUE =3
Member values can be anything: int, str, etc.. If the exact value is unimportant you may use auto instances and an appropriate value will be chosen for you. Care must be taken if you mix auto with other values.
🪄 Code:
from enum import Enum, autoclassPage(Enum): LOGIN =auto() DASHBOARD =auto() SEARCH =auto()classColor(Enum): RED =1 GREEN =2 BLUE =3# All enum members are hashable:color_settings_per_page ={ Page.LOGIN: Color.RED, Page.DASHBOARD: Color.GREEN, Page.SEARCH: Color.BLUE}print(color_settings_per_page)