Search code examples
pythonlistcoding-styletuplesimmutability

Tuples vs lists for module-level constants in Python?


Is it good style to use tuples rather than lists for module-level constant iterables in Python? For example, I have a list of important strings at the top of my file that I need to look for in my input:

IMPORTANT_STRINGS = [
  "Hello world!",
  "Goodbye world!",
  "Foo...",
  # etc --- there are about 40 entries
]

IMPORTANT_STRINGS will never be modified while my program is running.

On the one hand, I think that immutability is good and that I should prefer immutable data structures whenever possible, so I should use a tuple instead.

On the other hand, I think that tuples are more than just immutable lists: they're for heterogenous collections that should be used when you're passing around things like pairs, triples, etc --- fixed-size things whose size is important to what they are. I also don't think that I've ever seen Python code in the wild that uses tuples for constants like this, and it looks really strange to my eye to say:

IMPORTANT_STRINGS = (
   "Hello world!",
   etc
 )

Solution

  • Create a module, call it foo.py and insert the following:

    FOO = 'a', 'b'
    BAR = ['a', 'b']
    

    Now import them and see how they respond to in-place operations:

    >>> import foo
    >>> from foo import FOO, BAR
    >>> FOO += 'c', 'd'
    >>> BAR += 'c', 'd'
    >>> FOO
    ('a', 'b', 'c', 'd')
    >>> foo.FOO
    ('a', 'b')
    >>> foo.BAR
    ['a', 'b', 'c', 'd']
    

    As we can see, FOO, the tuple, remains in its original state as the canonical collection in the foo module. BAR on the other hand, can be mutated.

    Which should you prefer?

    It depends on what you want to happen when other modules access the collection. In many cases, we want other modules to be able to add to a canonical list. In some cases, we don't. The answer is to do what is appropriate given your circumstances and purposes and intentions for design and use.

    In your case, you say:

    IMPORTANT STRINGS will never be modified while my program is running.

    If they never should be modified, then tuples are fine. If you want your code to be useful to others who may need to share data in the same process, then you should go with a list.

    You mention:

    I think that tuples are more than just immutable lists: they're for heterogenous collections that should be used when you're passing around things like pairs, triples, etc --- fixed-size things whose size is important to what they are.

    Tuples are essentially immutable lists, and lists can have all kinds of objects in them too. Yes, fixed size, but that's really just a direct result from the immutability.

    Should you use tuples as immutable lists? I wouldn't. I would use lists on the theory that users of my code are responsible, and can handle modifying lists from modules they didn't write.

    Note that the ability of lists to be extended with tuples as demonstrated above means that you can generally start with tuples and then move to lists as needed.