# 44. Using functools.partial

Here are 10 Python code snippets demonstrating how to use `functools.partial` to create partially-applied functions, which simplify your code and increase reuse:

***

**1. Basic Partial Function**

Create a partial function with some arguments fixed.

```python
from functools import partial

def multiply(a, b):
    return a * b

# Create a new function with the second argument fixed
double = partial(multiply, b=2)

print(double(5))  # Output: 10
```

In this example, `double` is a partially-applied version of `multiply` with `b` fixed to `2`.

***

**2. Partially Apply Multiple Arguments**

Partially apply multiple arguments at once.

```python
from functools import partial

def power(base, exponent):
    return base ** exponent

# Create a function where the exponent is fixed to 3
cube = partial(power, exponent=3)

print(cube(4))  # Output: 64
```

Here, `cube` is a function that calculates the cube of a number, where `exponent` is pre-set.

***

**3. Default Arguments with Partial**

Use `partial` to create a function with default arguments.

```python
from functools import partial

def greet(name, message="Hello"):
    return f"{message}, {name}!"

# Create a function with the message pre-set to "Hi"
say_hi = partial(greet, message="Hi")

print(say_hi("John"))  # Output: Hi, John!
```

This code sets the `message` argument to "Hi" by default, while still allowing the `name` to vary.

***

**4. Using Partial for Callbacks**

Use `partial` to create a callback function with preset arguments.

```python
from functools import partial

def on_click(button, action):
    print(f"Button {button} clicked, action: {action}")

# Create a callback with a predefined button
button_click = partial(on_click, button="Save")

button_click(action="Save file")  # Output: Button Save clicked, action: Save file
```

Here, the `button` is fixed to "Save", and only the `action` varies when calling `button_click`.

***

**5. Simplify Function Calls with Partial**

Simplify repeated function calls with similar arguments.

```python
from functools import partial

def log_message(level, message):
    print(f"[{level}] {message}")

# Create a function for logging info messages
log_info = partial(log_message, level="INFO")

log_info("System started")  # Output: [INFO] System started
```

By fixing the `level` to "INFO", you create a more specialized function for logging information.

***

**6. Partial for Sorting with Custom Key**

Use `partial` to simplify sorting with a custom sorting key.

```python
from functools import partial

def sort_by_key(key, items):
    return sorted(items, key=lambda x: x[key])

# Create a function to sort by 'age'
sort_by_age = partial(sort_by_key, key="age")

data = [{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]
sorted_data = sort_by_age(data)

print(sorted_data)
```

This example creates a reusable `sort_by_age` function that sorts dictionaries by the "age" key.

***

**7. Function Composition with Partial**

Use `partial` to compose a series of functions.

```python
from functools import partial

def multiply(a, b):
    return a * b

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

# Partial function to multiply by 5
multiply_by_5 = partial(multiply, b=5)

# Compose add and multiply
result = add(2, multiply_by_5(3))

print(result)  # Output: 17 (2 + (3 * 5))
```

You can compose different functions using partials for code simplification and reuse.

***

**8. Partial for File Handling**

Use `partial` for common file-handling tasks with preset parameters.

```python
from functools import partial

def read_file(file_path, mode='r'):
    with open(file_path, mode) as file:
        return file.read()

# Create a function to read files as binary
read_binary = partial(read_file, mode='rb')

print(read_binary('some_file.txt'))
```

The `read_binary` function is a simplified version of `read_file` with the `mode` argument fixed to `'rb'`.

***

**9. Using Partial to Simulate Method Binding**

Simulate method binding with `partial`.

```python
from functools import partial

class Greeter:
    def greet(self, greeting, name):
        return f"{greeting}, {name}"

greeter = Greeter()

# Bind the method with a specific greeting
say_hello = partial(greeter.greet, greeting="Hello")

print(say_hello("John"))  # Output: Hello, John
```

Here, `say_hello` is a version of `greeter.greet` that always uses the greeting "Hello".

***

**10. Partial for Handling Database Queries**

Use `partial` to handle repeated queries in a database-like application.

```python
from functools import partial

def query_db(table, column, value):
    print(f"SELECT * FROM {table} WHERE {column} = {value}")

# Create a partial function for querying the 'users' table
query_users = partial(query_db, table="users")

query_users("username", "johndoe")  # Output: SELECT * FROM users WHERE username = johndoe
```

By using `partial`, we avoid repeating the `table="users"` argument in multiple queries.

***

These examples show how `functools.partial` can be used to simplify your code by creating specialized versions of functions, improving reusability, and reducing repetitive boilerplate.
