<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Carlos Saldaña</title>
    <description>The latest articles on DEV Community by Carlos Saldaña (@csalda3a).</description>
    <link>https://dev.to/csalda3a</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F492159%2F100251ec-0f45-4f66-af7a-1d84c679344b.jpg</url>
      <title>DEV Community: Carlos Saldaña</title>
      <link>https://dev.to/csalda3a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/csalda3a"/>
    <language>en</language>
    <item>
      <title>The Protocol Behind Python's Containers</title>
      <dc:creator>Carlos Saldaña</dc:creator>
      <pubDate>Tue, 19 May 2026 14:35:05 +0000</pubDate>
      <link>https://dev.to/csalda3a/the-protocol-behind-pythons-containers-10km</link>
      <guid>https://dev.to/csalda3a/the-protocol-behind-pythons-containers-10km</guid>
      <description>&lt;p&gt;Lists, tuples, dicts, and sets look like four different things. Underneath, they share the same idea: they all implement a small set of protocols, and once you see that, the rest stops feeling arbitrary. &lt;/p&gt;

&lt;h3&gt;
  
  
  What is a protocol?
&lt;/h3&gt;

&lt;p&gt;A protocol in Python is an informal contract defined by behavior, not by declaration. Anything that behaves like a sequence is a sequence, as far as Python cares. This style of typing has a name, it’s called structural typing, or as most of us know it, duck typing.("if it walks like a duck...").&lt;/p&gt;

&lt;p&gt;Think of this like the USB port. A USB port doesn't ask "are you a keyboard?" or "are you a hard drive?" It exposes a physical shape and a data protocol. Anything that fits the shape and speaks the protocol works.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Iterators and Iterables&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you only learn one thing about Python containers, learn the difference between an iterable and an iterator.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;strong&gt;iterable&lt;/strong&gt; is an object that we can iterate over, it's an object that can produce an iterator. To make this happen, it implements &lt;code&gt;__iter__()&lt;/code&gt;, which returns a fresh iterator each time it's called.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;iterator&lt;/strong&gt; is an object that &lt;em&gt;produces values one at a time&lt;/em&gt;. It implements &lt;code&gt;__next__()&lt;/code&gt; (and, by convention, &lt;code&gt;__iter__()&lt;/code&gt; returning &lt;code&gt;self&lt;/code&gt;). It raises &lt;code&gt;StopIteration&lt;/code&gt; when there are no more values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a few &lt;strong&gt;built-in iterables&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List&lt;/li&gt;
&lt;li&gt;Tuples&lt;/li&gt;
&lt;li&gt;Strings&lt;/li&gt;
&lt;li&gt;Dictionaries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s try an example to understand why a list is iterable but not an iterator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;list&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;iterator&lt;/span&gt;
&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;for&lt;/code&gt; loop is doing this exact dance. &lt;code&gt;for i in nums:&lt;/code&gt; it’s roughly doing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;_it&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_it&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s the whole &lt;strong&gt;protocol&lt;/strong&gt;. Once you understand this, things like &lt;code&gt;for&lt;/code&gt; loops, generators, &lt;code&gt;zip&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, comprehensions, unpacking, and &lt;code&gt;*args&lt;/code&gt; all start to work the same way in your mind.&lt;/p&gt;

&lt;p&gt;I'm more visual, so here's a sequence diagram showing the interaction over time between two objects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy5jbmzqnfmjaqja488fm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy5jbmzqnfmjaqja488fm.png" alt="A for loop" width="800" height="743"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Built-in Containers
&lt;/h3&gt;

&lt;p&gt;This is the good part. Most of us learn Python's containers at the surface: lists are mutable and ordered, tuples are immutable and ordered, dicts are key-value pairs, sets are unique and unordered. That's correct but also useless most of the time. It tells you nothing about performance. Nothing about why your set of dicts blew up with a TypeError. Nothing about why your queue is suddenly O(n²). &lt;/p&gt;

&lt;p&gt;Here's what to focus on instead. Every container in Python is three things at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A data structure: how it's stored in memory and how fast operations are.&lt;/li&gt;
&lt;li&gt;A set of protocols: the special methods it supports.&lt;/li&gt;
&lt;li&gt;A semantic choice: the meaning you communicate to other developers by using it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  List: the dynamic array
&lt;/h4&gt;

&lt;p&gt;A python list is a dynamic array (called a vector or &lt;code&gt;ArrayList&lt;/code&gt; in other languages).&lt;/p&gt;

&lt;p&gt;Under the hood, it’s a block of pointers to python objects, with extra space preallocated at the end for appending new items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────┬────┬────┬────┬────┬────┬────┬────┐
│ p0 │ p1 │ p2 │ p3 │ ▒▒ │ ▒▒ │ ▒▒ │ ▒▒ │   length=4, capacity=8
└────┴────┴────┴────┴────┴────┴────┴────┘
  ↑    ↑    ↑    ↑
  obj  obj  obj  obj

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one detail is what determines the entire complexity table.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lst[i]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lst.append(x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1) amortized&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lst.pop()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lst.pop(0)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lst.insert(0, x)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x in lst&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;len(lst)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Protocol:&lt;/strong&gt; &lt;code&gt;MutableSequence&lt;/code&gt; (which gives you &lt;code&gt;Sequence&lt;/code&gt; + &lt;code&gt;Iterable&lt;/code&gt; + &lt;code&gt;Container&lt;/code&gt; + &lt;code&gt;Sized&lt;/code&gt; + &lt;code&gt;Reversible&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic intent:&lt;/strong&gt; An ordered, mutable collection of items that I expect to iterate over, append to, and access by index.&lt;/p&gt;

&lt;p&gt;A common mistake is to use a &lt;code&gt;list&lt;/code&gt; as a FIFO queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is pretty expensive, the &lt;code&gt;pop(0)&lt;/code&gt; shifts every remaining element one position to the left, and remember this operation is &lt;code&gt;O(n)&lt;/code&gt;. If this runs inside a loop it can accidentally become &lt;code&gt;O(n²)&lt;/code&gt; .&lt;/p&gt;

&lt;h4&gt;
  
  
  Tuple: the record
&lt;/h4&gt;

&lt;p&gt;We think of tuples as immutable lists, but that idea can mislead. &lt;/p&gt;

&lt;p&gt;A tuple is better understood as a record: a fixed-size structure where each position can hold different types of data.&lt;/p&gt;

&lt;p&gt;In practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tuples represent structured data.&lt;/li&gt;
&lt;li&gt;Lists represent collections of items.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# List
&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;order1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...]&lt;/span&gt;

&lt;span class="c1"&gt;# Tuple
&lt;/span&gt;&lt;span class="n"&gt;db_row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;active&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Immutability is a result of this distinction, not the point. &lt;/p&gt;

&lt;p&gt;And because tuples are immutable, they gain a few important properties that lists don’t have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hashable&lt;/li&gt;
&lt;li&gt;Memory efficiency&lt;/li&gt;
&lt;li&gt;Read-only contract&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From a protocol perspective, tuples behave like read-only sequences and can also be hashable.&lt;/p&gt;

&lt;p&gt;Semantically, a tuple means: “This is a single thing identified by its contents.”&lt;/p&gt;

&lt;p&gt;This matters a lot in a production application, tuples are commonly used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compound dictionary keys&lt;/li&gt;
&lt;li&gt;Deduplication&lt;/li&gt;
&lt;li&gt;Cache and memoization keys&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Dict: the hash table
&lt;/h4&gt;

&lt;p&gt;The king. If lists are the most common container in Python, dictionaries are probably the most important. A big part of Python's internals is built on top of dictionaries. &lt;/p&gt;

&lt;p&gt;A dict is a hash table with open addressing. The keys you insert get hashed, and the hash points to a slot.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Average&lt;/th&gt;
&lt;th&gt;Worst&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;d[k]&lt;/code&gt;, &lt;code&gt;d[k] = v&lt;/code&gt;, &lt;code&gt;del d[k]&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n) (hash collisions)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;k in d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Iteration&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;From a protocol perspective, a &lt;code&gt;dict&lt;/code&gt; implements &lt;code&gt;MutableMapping&lt;/code&gt;, not &lt;code&gt;Sequence&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are two things you must remember about dictionaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keys must be hashable&lt;/li&gt;
&lt;li&gt;Insertion order is preserved&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Set: the dict without values
&lt;/h4&gt;

&lt;p&gt;A &lt;code&gt;set&lt;/code&gt; is almost the same thing as a dictionary, except it only cares about keys.&lt;/p&gt;

&lt;p&gt;It uses the same hash-table implementation underneath, which means it has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O(1) average-time lookups, inserts, and removals&lt;/li&gt;
&lt;li&gt;elements must be hashable&lt;/li&gt;
&lt;li&gt;same "no duplicates" guarantee, duplicates are naturally eliminated
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="c1"&gt;# the antipattern
&lt;/span&gt;&lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So in practice it's just a collection of unique keys. From a protocol perspective, a &lt;code&gt;set&lt;/code&gt; implements &lt;code&gt;MutableSet&lt;/code&gt;, which gives you built-in set operations like: &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;^&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Semantically, a set means: “I only care about uniqueness and fast membership checks.”&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;These are some of the most commonly used containers in Python in our applications, and it's important to understand the trade-offs when deciding which one to use. When you reach for a container, try to ask these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's the access pattern?&lt;/li&gt;
&lt;li&gt;Will it grow?&lt;/li&gt;
&lt;li&gt;Does identity-by-contents matter?&lt;/li&gt;
&lt;li&gt;What does the choice say to the reader?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the common bad choices we covered and what you should reach for instead:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You wrote&lt;/th&gt;
&lt;th&gt;You probably wanted&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;list.pop(0)&lt;/code&gt; in a loop&lt;/td&gt;
&lt;td&gt;&lt;code&gt;collections.deque&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;if x in big_list&lt;/code&gt; repeatedly&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;set&lt;/code&gt; (convert once)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;f"{a}:{b}"&lt;/code&gt; as a dict key&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;(a, b)&lt;/code&gt; tuple key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List of &lt;code&gt;(key, value)&lt;/code&gt; pairs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dict&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;dict[str, None]&lt;/code&gt; for membership&lt;/td&gt;
&lt;td&gt;&lt;code&gt;set&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tuple with named indexes everywhere&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;namedtuple&lt;/code&gt; or &lt;code&gt;dataclass&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you remember one thing: the container you pick is a contract, not a convenience.&lt;/p&gt;

</description>
      <category>python</category>
      <category>datastructures</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
