For the complete documentation index, see llms.txt. This page is also available as Markdown.

Fluent Python

My notes when reading Luciano Ramalho's Fluent Python.

The Python Data Model

By implementing special methods (A.K.A. magic methods, like __len__, __getitem__, __repr__ etc.. Often pronounced dunder xx), your objects can utilize built-in functions and syntax like len(), [], for ... in ... and thus be considered Pythonic.

Understanding the Pythonic len(xx) over xx.len(): Think of these functions as unary operators.

An Array of Sequences

  • List Comprehension vs Generator Expression

    • List Comprehension: list_a = [i + j for i in ... for j in ...]

    This is a cartesian products example. for i in ... part is the outer loop.

    • Generator Expression: xx(i + j for i in ... for j in ...)

    The syntactic difference is () vs []. 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

    • Tuples (Iterable) Unpacking

      • Use case: parallel assignment (can be nested), swap, % string formatting print('%s %s' % tup), passing function parameter f(*tup).

      • 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 b is [1, 2, 3]. Only one * prefix variable is allowed.

    • Named Tuples collections.namedtuple

      • Construction: Passing construct parameters by name or position. NamedTup._make(iterable). NamedTup(*iterable).

      • Accessing field by name or position.

      • ._asdict() return a collections.OrderedDict

    • Methods and attributes as an "immutable list": No appending/poping/inserting nor any inplace ops.

  • Slicing

    • [:3] exclude the last item.

    • Slice object.

      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[i:...]. If 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] = 100  
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      TypeError: can only assign an iterable
      >>> l[2:5] = [100]
      >>> l
      [0, 1, 100, 22, 9]
  • + and * 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)].

    • += and *= will first try to use __iadd__ and fall back to __add__ and create a new object.

  • list.sort and sorted

    • list.sort sorts inplace and returns None.

    • 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.

Misc

Last updated