Lesson 3 of 5

Collections

C# gives you a deliberate menu of collection types — Array, List<T>, Dictionary<K,V> — each with a generic type parameter enforced at compile time. Python gives you four built-in literals — list, tuple, dict, set — that hold anything, with no type parameter at all. Fewer types, less ceremony, less compile-time safety.

💡 The Bottom Line

List<T> maps to Python's list. Dictionary<K,V> maps to dict. There's no separate fixed-size array type you'll reach for day-to-day, and no generic type parameter to declare — a Python list can hold mixed types in the same list, whether you meant to or not.

Lists

C#
var names = new List<string> { "Ada", "Grace" };
names.Add("Linus");
Console.WriteLine(names[0]);
Console.WriteLine(names.Count);
Python
names = ["Ada", "Grace"]
names.append("Linus")
print(names[0])
print(len(names))

📋 Key differences

  • .Add().append().
  • .Count (a property) → len(names) (a built-in function, not a method).
  • No <string> type parameter — a Python list can hold ["Ada", 42, True] without complaint.
  • Negative indexing works out of the box: names[-1] is the last element — no .Last() LINQ call needed.

⚠️ Gotcha

Python's slicing looks like C#'s array[i] indexing but goes much further: names[1:3] returns a new list from index 1 up to (not including) index 3. It's easy to assume slicing behaves like List<T>.GetRange(), but the "exclusive end" convention and the ability to omit either side (names[:2], names[2:]) have no direct one-line C# equivalent — get comfortable with slicing early, it's everywhere in idiomatic Python.

Dictionaries

C#
var ages = new Dictionary<string, int>
{
    { "Ada", 36 },
    { "Grace", 85 }
};
Console.WriteLine(ages["Ada"]);
ages["Linus"] = 54;
Python
ages = {
    "Ada": 36,
    "Grace": 85,
}
print(ages["Ada"])
ages["Linus"] = 54

The shape is nearly identical — curly braces, key-value pairs, square-bracket access. The real difference is what happens on a missing key: C#'s indexer throws KeyNotFoundException, same as Python's ages["missing"] throwing KeyError. But Python also gives you ages.get("missing", 0) — a built-in "give me a default instead of throwing" — which in C# means reaching for TryGetValue instead.

Tuples and sets: no direct C# equivalent for one of them

Python's tuplepoint = (3, 4) — is an immutable, ordered group, similar in spirit to a C# ValueTuple ((3, 4) in modern C#) but used far more casually in everyday Python code, especially for returning multiple values from a function without declaring a class. Python's setcolors = {"red", "green"} — maps directly onto C#'s HashSet<T>: unordered, unique elements, fast membership checks with in.

🙋 There Are No Dumb Questions

Q: How do I get a fixed-size array like C#'s int[] arr = new int[5];?
A: Python's built-in list is always resizable — there's no separate fixed-size array type in everyday use. If you specifically need a fixed-size, single-type numeric array for performance (matching C#'s actual memory layout), that's what the third-party array module or NumPy's ndarray are for — but for typical business logic, a plain list is the idiomatic default, even where C# would reach for an array.

🔧 Try It Yourself

Take a C# method that builds a Dictionary<string, List<int>> (grouping numbers by a string key) and rewrite it in Python using a plain dict whose values are lists. Notice you never declare the value type anywhere — you just start appending to whichever list is at that key.

✅ Quick Check

Which Python built-in most directly corresponds to C#'s Dictionary<K,V>?


Next up: Python has classes too — but no interfaces, no access modifiers enforced by the compiler, and a very different idea of what "private" means. That's Classes & OOP.

← Back to
Next →