My notes when reading Luciano Ramalho's Fluent Python.
By implementing special methods (A.K.A. magic methods, like
__repr__ etc.. Often pronounced dunder xx), your objects can utilize built-in functions and syntax like
for ... in ... and thus be considered Pythonic.
Understanding the Pythonic
xx.len(): Think of these functions as unary operators.
List Comprehension vs Generator Expression
list_a = [i + j for i in ... for j in ...]
This is a cartesian products example.
for i in ... part is the outer loop.
xx(i + j for i in ... for j in ...)
The syntactic difference is
. But under the hood it saves space by yielding item one by one so a full list is never constructed. Also it can be used to build many other containers.
Tuples (Iterable) Unpacking
Use case: parallel assignment (can be nested), swap,
% string formatting
print('%s %s' % tup), passing function parameter
Works for any iterable as long as the iterable yields exactly one item per variable in the receiving end. The only exception is using
* dicussed below.
a, *b, c = range(5) and
[1, 2, 3]. Only one
* prefix variable is allowed.
Construction: Passing construct parameters by name or position.
Accessing field by name or position.
._asdict() return a
Methods and attributes as an "immutable list": No appending/poping/inserting nor any inplace ops.
[:3] exclude the last item.
s = slice(begin, end, stride)line[s]
Under the hood:
# v[a]v.__getitem__(a)# v[a, b]. Multidimensional. Used in Numpy.v.__getitem__((a, b))
Ellipsis object: function parameters
f(a, ..., z) and slice
a is four dimentional, this is a shortcut for
a[i, :, :, :]. It is mostly used in Numpy.
Assignment using slices. Some interesting example from the book:
>>> l = list(range(10))>>> l[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> l[2:5] = [20, 30]>>> l[0, 1, 20, 30, 5, 6, 7, 8, 9]>>> del l[5:7]>>> l[0, 1, 20, 30, 5, 8, 9]>>> l[3::2] = [11, 22]>>> l[0, 1, 20, 11, 5, 22, 9]>>> l[2:5] = 100Traceback (most recent call last):File "<stdin>", line 1, in <module>TypeError: can only assign an iterable>>> l[2:5] = >>> l[0, 1, 100, 22, 9]
* and augmented assignment on sequences
my_list = [] * 3 will result in a list with three references to the same inner list. List comprehension avoids this problem.
[ for i in range(3)].
*= will first try to use
__iadd__ and fall back to
__add__ and create a new object.
list.sort sorts inplace and returns
sorted library function accepts any iterable object.
Both accept two parameters:
reverse bool and
key for the name of a function that produces sorting keys.