pythonsequence

What kind of sequence are range and bytearray?


In the "Fluent Python" book by Luciano Ramalho (2nd ed.) he defines the concepts of container sequences and flat sequences:

A container sequence holds references to the objects it contains, which may be of any type, while a flat sequence stores the value of its contents in its own memory space, not as distinct Python objects.

Can we say that objects of type range and bytearray are flat sequences (I think that these objects can't contain references but not sure)?
And is there a simple way to test whether a sequence is flat or not?


I just found this post that gives a quote from the 1st edition of the "Fluent Python" book (I personally only have the 2nd edition):

Flat sequences: str, bytes, bytearray, memoryview, and array.array hold items of one type.

So, it seems that bytearray is a flat sequence. In the 2nd edition (p.22) the author says only that

Flat sequences – Hold items of one simple type. Some examples: str, bytes, and array.array.
Container sequences – Can hold items of different types, including nested containers. Some examples: list, tuple, and collections.deque.


Solution

  • You have it right about bytearray. It references an internal mutable memory space to hold objects of just one simple type (bytes), so it's a flat sequence, by the author's definition.

    A range object is a bit more tricky though. I'd say it doesn't match either of the criteria given by the author, though it's certainly a sequence. Rather than containing any values however, it just stores the start, stop and step arguments it's constructed with, and calculates what values it should contain on the fly, as they're needed. It doesn't reference them, as Python objects or otherwise, until then. This means you can create a range of any size in constant time, since nothing but a few integers needs to be allocated.

    A final note: The definitions of "flat sequence" and "container sequence" are not widely used in the Python development community. They may be useful in the context of your book to explain some differences in container behavior, but they won't be understood by Python programmers more widely. In general, the details of how a given container stores its contents are not usually something you need to care about. Leaving implementation details unspecified is often a deliberate choice by Python's design team, so that if a more efficient implementation becomes available, the code can be switched to it. This happened not long ago with Python's dictionaries, which became ordered (by insertion order) as a side effect of an implementation change. Because many of the previous implementation's details were unspecified, there was no break in backwards compatibility, since all the documented interfaces still worked the same way.