Skip to content
📖 Think AutoBook contents

Python Extras ​

The previous chapters cover the core features of Python (as expressed in Auto). But Python has many additional features that are useful and worth knowing. This chapter covers a selection of these extras.

Sets ​

A set is a collection of elements that is unordered and contains no duplicates. Auto provides HashSet from the standard library.

Creating and using a HashSet

How It Works

In Auto, HashSet is imported from std::collections. You can create a HashSet from a list literal -- duplicate values are automatically removed. The add and remove methods modify the set in place. Set operations like union (|), intersection (&), difference (-), and symmetric difference (^) work the same way in both Auto and Python.

Note for Python Programmers:

Auto uses HashSet<str> with explicit type parameters, while Python uses the built-in set type. Auto's HashSet requires importing from std::collections, but the operations are identical.

Sets are useful for removing duplicates from a collection and for checking membership efficiently. The in operator for sets is generally faster than for lists because sets use hash tables internally.

Counters and defaultdict ​

Python's collections module provides Counter and defaultdict, which are convenient wrappers around dictionaries. In Auto, you can achieve the same results with regular dictionaries and helper functions.

List comprehensions and counting patterns

How It Works

Auto does not have list comprehensions. Instead, you use explicit for loops with append. The resulting Python code from the a2p transpiler also uses for loops rather than comprehensions, which some may find more readable.

For counting, Auto uses the HashMap.get(key, default) pattern instead of Python's Counter. For grouping (the defaultdict pattern), you check if the key exists and initialize it if not.

Note for Python Programmers:

Auto uses HashMap explicitly rather than Python's dict. The a2p transpiler converts Auto's HashMap<K, V> to Python's dict. While Python has Counter and defaultdict for convenience, Auto achieves the same results with a few extra lines of explicit code.

Conditional expressions ​

Python has a conditional expression, also called a "ternary operator," which allows you to write an if/else in a single expression. Auto supports the same pattern.

auto
let x = 5
let label = if x < 10 { "low" } else { "high" }
print(label)  // low

The equivalent in Python:

python
x = 5
label = "low" if x < 10 else "high"
print(label)  # low

Conditional expressions are often shorter than an if statement, but they are not always easier to read. Use them when the logic is simple and the expression is short.

Named tuples ​

A named tuple is a tuple where each element has a name. Named tuples are useful when you want a simple object with named attributes, but you don't need the full functionality of a class.

In Auto, you achieve the same thing with a type definition, which is more explicit and provides the same benefits.

Named tuples using Auto type definitions

How It Works

In Auto, a type definition serves the same purpose as Python's namedtuple. Both provide objects with named attributes. Auto's type is more flexible -- you can add methods, use default values, and define custom behavior.

The a2p transpiler converts Auto's type definitions into Python classes with __init__, __eq__, and comparison methods as needed.

Note for Python Programmers:

Python's namedtuple is lightweight and immutable. Auto's type is also lightweight but is mutable by default. If you want immutability, use let for the fields. The a2p transpiler generates Python classes rather than namedtuple instances, giving you more control over behavior.

any and all ​

Python provides built-in functions any and all that take an iterable of boolean values and return a single boolean result.

  • any returns true if at least one element is truthy.
  • all returns true if all elements are truthy.

In Auto, you can use these functions from the standard library, or implement the logic yourself with a loop.

Conditional expressions, any, and all

How It Works

Auto's conditional expression syntax is if condition { value1 } else { value2 }, which is similar to Python's value1 if condition else value2 but with the condition first (like an if statement). For chained conditions, Auto nests the expressions naturally.

The any and all functions work the same in both Auto and Python. They take an iterable and return a boolean. In Auto, when you need early termination (like break), you use explicit loops instead of generator expressions.

Note for Python Programmers:

Python's conditional expression puts the value first: x if condition else y. Auto puts the condition first: if condition { x } else { y }. Python's generator expressions (like any(x &gt; 0 for x in numbers)) don't have a direct Auto equivalent -- use explicit loops instead.

Debugging ​

When you are working with sets, dictionaries, and other collections, there are a few common sources of errors:

Mutable default arguments: In Python, using a mutable object (like a list or dict) as a default argument can cause unexpected behavior because the same object is shared across all calls. In Auto, default values are evaluated each time, so this is not an issue.

Set/dict key types: Only immutable types can be used as keys in a dictionary or elements in a set. In Python, this means strings, numbers, and tuples of immutables. Auto follows the same rule -- you cannot use a list as a dictionary key.

Modifying while iterating: Modifying a collection while iterating over it can cause errors or unexpected behavior. If you need to modify a collection during iteration, iterate over a copy.

auto
// WRONG: modifying list while iterating
let mut items = [1, 2, 3, 4, 5]
for item in items {
    if item == 3 {
        items.remove(item)  // undefined behavior!
    }
}

// CORRECT: collect items to remove, then remove them
let mut items = [1, 2, 3, 4, 5]
let mut to_remove: [int] = []
for item in items {
    if item == 3 {
        to_remove.append(item)
    }
}
for item in to_remove {
    items.remove(item)
}

Glossary ​

set: An unordered collection of unique elements. In Auto, represented by HashSet.

HashSet: Auto's set type, imported from std::collections.

set operation: Operations like union (|), intersection (&), difference (-), and symmetric difference (^) that combine sets.

Counter: A dictionary that maps elements to their frequencies. In Python, provided by collections.Counter. In Auto, implemented with a regular HashMap.

defaultdict: A dictionary that provides a default value for missing keys. In Python, provided by collections.defaultdict. In Auto, implemented with explicit key checking.

list comprehension: A Python expression that creates a list by applying an expression to each element of an iterable, optionally filtered by a condition. Auto uses explicit for loops instead.

conditional expression: An expression that returns one of two values depending on a boolean condition. Also called a "ternary operator."

named tuple: A tuple with named elements. In Auto, achieved with a type definition.

any: A function that returns true if at least one element of an iterable is truthy.

all: A function that returns true if all elements of an iterable are truthy.

Exercises ​

Exercise 1 ​

Write a function called has_duplicates that takes a list and returns true if any element appears more than once. It should not modify the original list.

Exercise 2 ​

Write a function called word_frequency that takes a string and returns a dictionary that maps each word to the number of times it appears. Convert the string to lowercase and remove punctuation before counting.

Exercise 3 ​

Write a function called unique_words that takes a list of words and returns a list of the unique words in alphabetical order, using a HashSet.

Exercise 4 ​

Python's dict has a method called setdefault that sets a value in a dictionary only if the key is not already present. The equivalent in Auto is:

auto
let mut d: HashMap<str, [int]> = {}
// Instead of d.setdefault(key, []).append(value):
if key not in d {
    d[key] = []
}
d[key].append(value)

Use this pattern to write a function called invert_dict that takes a dictionary and returns a new dictionary where the keys and values are swapped. If the original dictionary has duplicate values, the inverted dictionary should map each value to a list of keys.

Released under the MIT License.