RUNTIME VALUE CONVERSIONS
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.
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.
| Form | Behavior |
|---|---|
[], [value, ...] | Empty or populated lists with mixed and nested supported values. |
values[index], values[index] = value | Calculated 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 *= count | Mutate the shared list. The right operand of += may be any admitted iterable. |
left + right, values * count | Create 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 not | Compare 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].
|
PyCForge caveats Make set output order explicit. Python and generated C may enumerate the same set in different orders. For reproducible reports or Python/C comparisons, sort mutually comparable elements, as |
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.
| Form | Behavior |
|---|---|
{}, {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 |= source | Union 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 d | Count entries, test nonemptiness, or test key membership. |
==, !=, is, is not | Compare 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.
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
{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.
| Form | Behavior |
|---|---|
len, bool, iteration, in, not in | Inspect 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_difference | The 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, update | Change 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_update | Update 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.
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.
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.
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.
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.