---
# System prepended metadata

title: 12-02 Functions
tags: [Unit 6 - Functions]

---

Heavenly Father,
We come before You with hearts seeking wisdom and discernment. We live in a world filled with wonders and conveniences, where the works of human hands and minds often conceal the deeper truths and complexities of creation. So we ask for Your guidance, Lord, to see beyond the surface, to discern where ease and efficiency have replaced the depth of experience and meaning. Help us not to hide behind “black-boxes” that obscure what is good, true, and beautiful in the fabric of life. Teach us to be present, mindful, and involved — not merely consumers of products, but stewards of the processes that sustain and connect us.
May we seek to engage with the world You made in a way that reflects Your image in us — with curiosity, reverence, and responsibility. Give us wisdom to resist the temptation of shortcuts that disconnect us from the richness of life. May we never trade the fullness of Your creation for the hollow promise of instant gratification. Draw us deeper into the truth, that in all we do we may seek to honor You.
In Jesus' name, we pray,
Amen.

# Retrieval exercise
Observe the following code. It uses the GUIZero module. Try to run it and understand it.

```python
from guizero import App, TextBox, Combo, PushButton, Text

def calculate_result():
    try:
        # Read numbers from input boxes
        num1 = float(input_box1.value)
        num2 = float(input_box2.value)
        
        # Get the selected operation
        operation = operation_box.value
        
        # Perform the calculation based on the selected operation
        if operation == "+":
            result = num1 + num2
        elif operation == "-":
            result = num1 - num2
        elif operation == "*":
            result = num1 * num2
        elif operation == "/":
            result = num1 / num2 if num2 != 0 else "Error: Division by zero"
        else:
            result = "Invalid Operation"
        
        # Update the result Text widget
        result_text.value = f"Result: {result}"
    except ValueError:
        result_text.value = "Error: Invalid Input"

# Create the GUI
app = App(title="Simple Calculator")

# Input widgets for numbers
input_box1 = TextBox(app, width=10)
input_box2 = TextBox(app, width=10)

# ComboBox for selecting operation
operation_box = Combo(app, options=["+", "-", "*", "/"])

# Button to trigger the calculation
calculate_button = PushButton(app, text="Calculate", command=calculate_result)

# Text widget to display the result
result_text = Text(app, text="Result: ")

# Start the GUI
app.display()
```

Some tasks you may want to implement:
- Try to implement a new option, for exponentiation (“first number ** second number”)
- Put a new button that clears the text boxes when pressed

# Docstrings
Docstrings are a type of documentation string used in Python to describe what a module, class, method, or function does. They provide a convenient way to document code so that other developers (or even yourself, at a later time) can understand its purpose and usage more easily. They are written as a string literal immediately after the definition of a module, class, or function and are accessible via the built-in `help()` function or the special `__doc__` attribute.

Why Use Docstrings?
- Clarity: Docstrings make it easier for others to understand your code.
- Documentation: They serve as in-code documentation for functions, classes, and methods.
- Tool Integration: Many tools like pydoc and IDEs use docstrings for generating documentation automatically.

```python
def multiply(a, b):
    """
    Multiply two numbers and return the result.

    This function takes two numbers as input and returns their product.
    It handles both integer and floating-point numbers.

    Parameters:
    a (int, float): The first number to multiply.
    b (int, float): The second number to multiply.

    Returns:
    int, float: The product of a and b.
    """
    return a * b
```

# Lambda functions
A lambda function is a small and unnamed function defined using the keyword `lambda` instead of the standard `def` keyword. It’s primarily used for short, simple operations where defining a separate function using def might feel unnecessary.
The syntax of a lambda function is:
```python
lambda arguments: expression
```

- `arguments`: The input values the lambda function takes (similar to parameters in a standard function).
- `expression`: The single expression that the lambda function evaluates and returns. Note that there can only be a single line of code in a lambda function.

For example, a standard function to add two numbers might look like this:

```python
def add(a, b):
    return a + b
```

The equivalent lambda function would be:
```
add = lambda a, b: a + b
```

You can use this lambda function just like a normal function: `print(add(2, 3))  # Output: 5`

## Mapping lambda functions

Now, suppose we write this:

```python
born_year = list(map(lambda age: 2024 - age, ages))
```

- What does the lambda function `lambda age: 2024 - age` do for each element in the ages list?
- Suppose you implement this function without a lambda function. How would you then use it? What is the difference between running a loop and using a map() function?

> A note: today, the use of mapping functions instead of running loops is widely used and recommended in many areas!

## Filtering with lambda functions

Suppose we have a list of numbers representing the ages of people in a community:
```python
ages = [5, 12, 17, 24, 35, 42, 58, 72]
```

We then write this line of code:

```python
adults = list(filter(lambda age: age >= 18, ages))
```

Questions:
- What does the lambda function lambda age: age >= 18 do for each element in the ages list?
    - Hint: If age is 17, what does the lambda function return? What happens if age is 24?
- What does the filter() function do when the lambda returns `True` for an element?

## Sorting with lambda functions

Look at this example. How does it work?

```python
def sort_by_last_name_lambda(names):
    return sorted(names, key=lambda full_name: full_name.split()[-1])

# Example usage:
names = ["John Smith", "Jane Doe", "Alice Johnson", "Bob Brown"]
print(sort_by_last_name_lambda(names))
```

## Practicing some other string methods
You have a list of book titles as strings:

```python
books = [
    "War and Peace",
    "Pride and Prejudice",
    "The Great Gatsby",
    "Moby Dick",
    "To Kill a Mockingbird",
    "Brave New World",
    "The Catcher in the Rye",
    "Great Expectations"
]
```

- Implement a function called `shorten_titles` that shortens each book title to its first three words (if the title has more than three words). Use a combination of a lambda function and a string method inside `map()` to achieve this.
- Implement a function called `sort_by_title_length` that sorts the book titles by the number of characters in each title (excluding spaces). Use a lambda function and a suitable string method inside `sorted()`.
- Test both functions and print the results.

# Functions mediate actions
Functions, as every technological tool, give us the power to do something. However…

- I only have the power to do something with a tool if I submit to the rules of the tool
![image](https://hackmd.io/_uploads/SJK_8l0Xyg.png)

- I only have the power to do something with a technology if I submit to the world that makes the technology possible.
![image](https://hackmd.io/_uploads/ryrK8eCQ1l.png)

Let’s represent this as a network of mediators:
![image](https://hackmd.io/_uploads/SkxqLgCQJx.png)

Can you think about more actors in this network? (By the way, this type of analysis is commonly referred as Actor-Network Theory)

Thus: **one doesn’t simply ‘use’ a technology. You also ‘use’ the whole world around the technology**. If someone does something, everyone is also doing something. The actor is the network, the network is the actor. This is also referred to as an [assemblage](https://en.wikipedia.org/wiki/Assemblage_(philosophy)).
![image](https://hackmd.io/_uploads/rkKqIlAX1x.png)

Think about more examples…
> “Technology produces, defines and constrains a series of subsequent options that can be selected by the user, and the selection of these options depends, in turn, on a broader technological application. In short, we are not free to use various technologies in the way we choose, [since] whoever chooses is shaped by the choices being made or contemplated. Moral vision, and therefore also moral evaluation, is enveloped by a set of values that are imposed by technological potential rather than the other way around.” –George Grant, Technology and Empire

How does that happen in programming? To achieve something with programming, you need:
- A standardized programming language (eg. Python)
- Other libraries and functions implemented in Python
- A Python compiler/interpreter
- An operating system which runs Python, its compiler/interpreters, and its libraries (Windows, Linux, Mac)
- A PC or other similar device, which requires:
- Microelectronics and hardware industry
- Industrial standards and interfaces (IEEE, ISO), etc.
What more?

Question: is it a good thing to rely on all the mediators around our technology? Could we be accomplices in propagation of evil?
