Course outline

Python / Foundations / Lesson 5

Collections and Unicode text

Choose collections by access pattern, understand aliasing and copying, and process text without losing its meaning.

About 4 min readContent reviewed
On this page

Lesson goals

  • Choose by responsibility
  • Text is not encoded bytes

Choose by responsibility

A list is an ordered mutable sequence, a tuple is an ordered immutable sequence, a dictionary associates unique keys with values, and a set stores distinct hashable elements. Choose based on operations rather than appearance: an ordered activity log suggests a list, while a count by product code suggests a dictionary. Dictionaries preserve insertion order, but sets do not provide a meaningful display order. Sort a set when deterministic output matters. A tuple prevents replacing its own elements, but an element can still refer to a mutable object; immutability of a container does not recursively freeze everything reachable through it.

Indexing, slicing, and membership

Sequence indexing starts at zero, and negative indices count from the end. A slice such as values[1:4] includes the start and excludes the stop; it can be empty without raising an error. Directly indexing beyond the available positions raises IndexError. Membership with in asks whether an item exists rather than where it is located. For a dictionary it tests keys, so use values() when the requirement concerns values. A clear access pattern prevents unnecessary scanning and avoids conflating missing data with a legitimate zero or empty string. Choose explicit defaults only when the domain truly treats absence that way.

Count with a dictionary

A dictionary makes aggregation explicit: each key identifies a category, and each value stores its accumulated count. The get method supplies a default without inserting it by itself. Updating the assignment then records the new count. Normalization should happen before lookup if differently cased words are meant to share a category. The example uses casefold, a Unicode-oriented case normalization operation, and sorts keys for a stable report. This is a policy choice rather than a universal rule: preserving distinctions may matter for identifiers, personal names, or case-sensitive external systems. Never normalize away information without checking the requirement.

python Count with a dictionary — worked example
words = ["Tea", "tea", "Bread"]
counts = {}
for word in words:
    key = word.casefold()
    counts[key] = counts.get(key, 0) + 1
for key in sorted(counts):
    print(key, counts[key])
Expected output
bread 1
tea 2

Both spellings of tea share one normalized key. Sorting determines the report order rather than depending on the order of input categories.

Aliasing and shallow copies

Assigning a collection to another name creates another reference to the same object. list.copy creates a new outer list, but its elements still refer to the original nested objects. This is a shallow copy. Changing an inner list is visible through both outer lists; replacing an outer element is confined to the outer list being changed. The example separates those operations. A deep copy can duplicate nested structures, but it is not a substitute for understanding ownership and may be inappropriate for resources or shared identities. Prefer clear data boundaries and deliberately choose which nested parts need independence.

python Aliasing and shallow copies — worked example
original = [[1], [2]]
copy = original.copy()
copy[0].append(9)
copy[1] = [7]
print(original)
print(copy)
Expected output
[[1, 9], [2]]
[[1, 9], [7]]

The first inner list is shared and changes in both views. Replacing the second element changes only the new outer list.

Text is not encoded bytes

Python str represents Unicode text, while bytes represents encoded byte sequences. Encode text when communicating with a byte-oriented boundary and decode bytes with the agreed encoding. UTF-8 is a common explicit choice, but an external format’s documented encoding wins. len(text) counts Unicode code points, which need not equal user-perceived characters or screen width; combining marks and emoji sequences expose that distinction. String methods return new strings because strings are immutable. Keep exact original text when audit or display requirements need it, and use a separate normalized value for comparison. This avoids silently rewriting meaningful user input.

Common errors and fixes

A lookup raises KeyError for an optional field

Why it happens
Direct indexing assumes the key is present.
How to fix it
Use get with a meaningful default or validate required keys first.
Prevent it next time
Document which fields are required and which can be absent.

A copy changes its original nested data

Why it happens
The copy duplicates only the outer container.
How to fix it
Copy the specific nested parts requiring independent ownership.
Prevent it next time
Test nested mutations as well as outer replacements.

A set report changes order between runs

Why it happens
Set iteration order is not a presentation contract.
How to fix it
Sort elements before displaying comparable output.
Prevent it next time
Make ordering an explicit reporting decision.

Check your understanding

1. Remove duplicates from ["b", "a", "b"] and produce alphabetical output.

Show worked solution

Convert the list to a set to express distinct membership, then call sorted on that set. sorted(set(["b", "a", "b"])) returns ["a", "b"]. The set removes duplication; sorting establishes the separate output-order requirement.

2. Explain why len("é") and the number of UTF-8 bytes can differ.

Show worked solution

The precomposed character é is one Unicode code point but its UTF-8 representation uses two bytes. len("é") is 1, while len("é".encode("utf-8")) is 2. Text length and encoded storage length answer different questions and must not be interchanged in limits.

Key takeaways

  • Choose collections for the operations they must support.
  • Shallow copies retain references to nested objects.
  • Unicode text and encoded bytes have different lengths and roles.

Official references