Effective Python 71 - 75

Click here for the first post, which contains the context of this series.

Item #71: Prefer deque for producer-consumer queues.

  • The list type can be used as a FIFO queue by having the producer call append to add items and the consumer call pop(0) to receive items. However, this may cause problems because the performance of pop(0) degrades superlinearly as the queue length increases.
  • The deque class from the collections built-in module takes constant time—regardless of length—for append and popleft, making it ideal for FIFO queues.

Item #72: Consider searching sorted sequences with bisect.

  • Searching sorted data contained in a list takes linear time using the index method or a for loop with simple comparisons.
  • The bisect built-in module’s bisect_left function takes logarithmic time to search for values in sorted lists, which can be orders of magnitude faster than other approaches.

Item #73: Know how to use heapq for priority queues.

  • Priority queues allow you to process items in order of importance instead of in first-in, first-out order.
  • If you try to use list operations to implement a priority queue, your program's performance will degrade superlinearly as the queue grows.
  • The heapq built-in module provides all of the functions you need to implement a priority queue that scales efficiently.
  • To use heapq, the items being prioritized must have a natural sort order, which requires special methods like __lt__ to be defined for classes.

Item #74: Consider memoryview and bytearray for zero-copy interaction with bytes.

  • The memoryview built-in type provides a zero-copy interface for reading and writing slices of objects that support Python's high-performance buffer protocol.
  • The bytearray built-in type provides a mutable bytes-like type that can be used for zero-copy data reads with functions like socket.recv_from.
  • A memoryview can wrap a bytearray, allowing for received data to be spliced into an arbitrary buffer location without copying costs.

Item #75: Use repr strings for debugging output.

  • Calling print on built-in Python types produces the human-readable string version of a value, which hides type information.
  • Calling repr on built-in Python types produces the printable string version of a value. These repr strings can often be passed to the eval built-in function to get back the original value.
  • %s in format strings produces human-readable strings like str. %r produces printable strings like repr. F-strings produce human-readable strings for replacement text expressions unless you specify the !r suffix.
  • You can define the __repr__ special method on a class to customize the printable representation of instances and provide more detailed debugging information.