Need to perform the same operation in several places? Define a function instead of copying its code. A function accepts arguments, performs an operation, and produces a return value. Keeping shared behavior in one place makes later changes easier. section 3.6.1 section 6.0
Give sorting a purpose-built function
To sort task dictionaries by urgency, define a key function that accepts one task and returns the value to sort by: ```python def using_urgency_level(task): return task['urgency'] tasks.sort(key=using_urgency_level, reverse=True) ``` For tasks with urgency values 5, 3, and 2, the resulting order is 5, 3, then 2. Pass the function itself as `key`; sorting calls it for each item. section 3.2.3
Make a function straightforward to call and understand:
- Prefer one clear purpose and usually one returned value. If a function has no explicit `return`, its return value is `None`; returning multiple values produces a tuple. section 6.2.2 section 6.2.4
- Use defaults for arguments that usually have the same value, but use `None` rather than a mutable list as a default. Add parameter and return type hints to clarify the call. section 6.6 section 6.3.2
- Use a fixed set of arguments most of the time. When a call genuinely needs a variable number, `*args` accepts positional arguments and `**kwargs` accepts keyword arguments. section 6.6 section 6.4
An effect is not the return value
```python def append_task(task, grouped_tasks): grouped_tasks.append(task) result = append_task('Homework', []) print(result) # None ``` The function appends to the supplied list, but does not explicitly return the list. Check what a function returns rather than assuming its effect is also its output. section 6.2.2
Python also treats functions as objects. You can pass one as a sorting key, store functions in a dictionary, or return an inner function from another function. A function that accepts or returns a function is a higher-order function. Callability alone does not identify a function: classes and instances implementing `__call__` can be callable too. section 7.2 section 10.5.1
Listing 7.4 Saving functions in a dict object
actions = {"mean": get_mean, "min": get_min, "max": get_max}
def fallback_action(data): #1
return "error in action"
def process_data(data, action):
calculation = actions.get(action, fallback_action)
processed = calculation(data)
return processed
A dictionary maps action names to functions. Looking up and calling the selected function replaces several `if...elif...else...` branches; an unknown action uses a fallback function. section 7.2.1
Test a function with a specific input and an expected output. For example, a task-creation function can be checked against the expected task data with `assert`. This tests the behavior even if the implementation later changes. section 13.3.1



















