RUNTIME VALUE CONVERSIONS

Lists, dictionaries, sets, and tuples

Use runtime containers to share mutable data, retain ordered entries, or collect unique values. Lists, dictionaries, and tuples can contain mixed and nested supported values; set elements must be hashable.

Share and change a list

def update(values: list[int | str]) -> None:
    values[0] = "changed"
    values.append(9)

def shared_values() -> list[int | str]:
    values: list[int | str] = [1, "two"]
    alias = values
    update(alias)
    return values

shared_values() returns ["changed", "two", 9]. Assignment and function calls keep the same list object; they do not make independent copies.

Supported list operations

FormBehavior
[], [value, ...]Empty or populated lists with mixed and nested supported values.
values[index], values[index] = valueCalculated integer indices; negative indices count from the end.
values.append(value)Add one element to the same list.
extend(iterable), insert(index, value)Add an iterable or insert at a clamped index; self-extension duplicates the original elements once.
pop(index=-1), remove(value), clear()Pop returns the removed element; remove deletes the first equal value. Clear empties the same list. Missing values or indices report errors.
sort(key=None, reverse=False), reverse()Change the same list and return None. Sort accepts keyword arguments only.
copy(), index(value, start, stop)Shallow copy or first matching position within optional integer bounds. Tuple index is also supported.
values += other, values *= countMutate the shared list. The right operand of += may be any admitted iterable.
left + right, values * countCreate a new outer list; concatenation requires two lists.
values[start:stop:step]Create a shallow slice, including negative steps. Assign an iterable to replace the slice; steps other than 1 require the same number of replacement elements.
del values[index], del values[start:stop:step]Remove an element or slice from the same shared list.
len, iteration, in/not in, count(value)Inspect elements in sequence order.
==, !=, is, is notCompare list contents or test shared list identity.

Nested mutable elements remain shared in slices, copies, concatenation, and repetition. Slice replacement snapshots its input before changing the list, so self-assignment works. Sort is stable, evaluates keys once, and reports mutation of the target during sorting.

def main() -> int:
    values = [3, 1, 2, 1]
    alias = values
    values[1:3] = [8, 9]
    unique = {value for value in values}
    print(alias, sorted(unique))
    return 0

This prints [3, 8, 9, 1] [1, 3, 8, 9].

Ordered mutable dictionaries

Runtime dictionaries preserve insertion order and shared identity across variables, calls, class fields, and nested containers. Lookup uses a hash index; replacing a value preserves the original key and position. Deleting then reinserting a key appends it at the end.

def word_counts(text: str) -> dict[str, int]:
    counts: dict[str, int] = {}
    for word in text.lower().split():
        counts[word] = counts.get(word, 0) + 1
    return counts

def main() -> int:
    counts = word_counts("Python C Python café CAFÉ")
    for word, count in counts.items():
        print(word, count)
    return 0

This prints python 2, c 1, and café 2 on separate lines in first-seen order.

FormBehavior
{}, {key: value, ...}, dict()Create an ordered dictionary. Duplicate equal keys keep their first position and last value.
dict(source, name=value), d.update(source, name=value)Copy or merge a dictionary or an admitted iterable of key/value pairs, then apply explicit keywords. The source is optional. Update changes the existing object and returns None.
left | right, {**left, **right}, d |= sourceUnion and unpacking combine dictionaries; later values win without moving existing keys. In-place union also accepts key/value iterables and preserves shared identity.
dict.fromkeys(iterable, value=None)Create entries with one shared value. Duplicate equal keys keep their first position.
d[key], d[key] = value, del d[key]Read, replace, insert, or delete. Missing reads and deletions report KeyError.
d.get(key, default), d.setdefault(key, default)Read with a fallback, or insert and return the fallback when absent. Omitted defaults are None.
d.pop(key, default), d.popitem()Remove and return a value, or the last inserted key/value tuple. Missing pop without a default and popitem on an empty dictionary report KeyError.
d.copy(), d.clear()Create a shallow independent outer dictionary, or remove all entries from the same object. Nested mutable values remain shared.
len(d), bool(d), key in dCount entries, test nonemptiness, or test key membership.
==, !=, is, is notCompare contents independently of insertion order, or test shared identity.

Keys may be strings, signed 64-bit integers, finite floats, Booleans, None, or recursively hashable tuples and frozen sets of these. Equal numeric keys share an entry: 1, 1.0, and True are equivalent keys. Mutable containers, objects, functions, ranges, and slices are outside the key profile. Values may be any supported runtime value.

Live keys, values, and items

d.keys(), d.values(), and d.items() return live views. Their lengths and future iterations reflect changes to the dictionary. Iterate directly, use membership tests, or materialize a snapshot with list(view) or tuple(view). Iterating a dictionary itself yields keys; items yields key/value tuples. Use reversed(d) or reversed(view) for reverse insertion order.

Replacing existing values during iteration is supported. Adding, deleting, or clearing keys during an active iteration reports RuntimeError, including delete/reinsert operations that keep the size unchanged. This explicit profile is stricter than some Python iterator cases. Iterate over list(d) when changing keys. Views have no indexing, slicing, ordering, equality, or set operations in this profile.

Custom mapping protocols and nonempty dictionary format specifications are unsupported. Use the documented dictionary operations and representations.

Example: inspect a live view, then remove completed entries safely. Snapshot the keys before changing dictionary structure:

def main() -> int:
    counts = {"done": 0, "todo": 2}
    keys = counts.keys()
    counts["later"] = 1
    print(len(keys))
    for name in list(keys):
        if counts[name] == 0:
            del counts[name]
    for name, count in counts.items():
        print(name, count)
    return 0

Expected output:

3
todo 2
later 1

Sets and frozen sets

{value, ...} and set(iterable) create mutable sets; frozenset(iterable) creates immutable sets. Empty constructors are supported. Elements follow the dictionary key rules above. Equal numeric values share one entry. Iteration, printing, and pop order are unspecified; use sorted(values) when an ordered result is required.

FormBehavior
len, bool, iteration, in, not inInspect elements. A set has no index or slice.
|, &, -, ^Union, intersection, difference, or symmetric difference. Both operands must be sets; the result has the left operand's set kind.
union, intersection, difference, symmetric_differenceThe corresponding methods accept admitted iterables. The first three accept multiple iterables; symmetric difference accepts one.
==, !=, <, <=, >, >=Equality and proper/nonproper subset or superset comparisons. Methods issubset, issuperset, and isdisjoint also accept iterables.
add, remove, discard, pop, clear, updateChange a mutable set shared by its aliases. Remove requires an existing element; discard tolerates an absent one. Pop returns an arbitrary element and fails on an empty set.
|=, &=, -=, ^=; intersection_update, difference_update, symmetric_difference_updateUpdate the same mutable set. Operators require sets; methods accept iterables. Frozen-set operators produce a replacement value.
copy()Copy a mutable set; a frozen-set copy can reuse the immutable object.

Changing a set's elements during active iteration reports RuntimeError, including changes that preserve its size. Adding an already-present element does not invalidate iteration. Use a snapshot when removing elements in a loop. Frozen sets can be dictionary keys or elements of other sets.

Methods consume iterator arguments as needed; intersection and subset/superset checks can stop before exhaustion. Later uses of the same iterator continue from that position. In-place difference removes items as they are read, so an error can leave earlier removals in effect.

Different types at tuple positions

def describe(name: str, count: int) -> tuple[str, int, bool]:
    row: tuple[str, int, bool] = (name, count, count > 0)
    return row

tuple[str, int, bool] checks each position separately. Use tuple[int, ...] for a variable-length tuple of integers. Unannotated tuples can also contain mixed supported values.

Immutable tuple slots, shared contents

def nested_values() -> tuple[str, list[int]]:
    values = [1, 2]
    row = ("items", values)
    row[1].append(3)
    return row

The result is ("items", [1, 2, 3]). A tuple slot cannot be replaced, but a list referenced by that slot can change. Tuples support indexing, slices, concatenation with tuples, repetition, equality, membership, count(value), and iteration. Identity tests for numbers, strings, and tuples are unsupported; use equality for value comparisons. is None and is not None are supported for optional values.

Packing, conversion, and unpacking

def unpack_row(row: tuple[str, int]) -> str:
    name, count = row
    return name + ": " + str(count)

Unpack any admitted iterable, including dictionary keys and views. Fixed targets require a matching element count. One starred target at each nesting level collects the remaining elements into a new list; nested targets and loop targets are supported. List, tuple, and set displays also accept *iterable entries. list(value) and tuple(value) accept any admitted iterable, including sets, frozen sets, dictionary views, and readable files. A string yields one-character strings. list() and tuple(), or [] and (), create empty containers.

Container annotation checks

list[int | str] accepts integer and string elements at an annotated boundary. These checks inspect the current contents; they do not attach a permanent element schema to the shared object. A later write through an alias can change contents, and the next annotated boundary checks them again. See Function and assignment checks.

Container growth is constrained by the runtime context's memory and work limits. dict[K, V] checks every current key and value at annotated boundaries. set[T] and frozenset[T] check their elements at these same boundaries. Typed conversion retains its fixed-container forms.