01_advanced_functions.py
Python/02_intermediate_level/01_advanced_functions.py
"""
Advanced Functions - Taking Functions to the Next Level
This file contains all the example code from the Advanced Functions lesson.
"""
# Default and Keyword Arguments
# Default Parameters
def greet_user(name, greeting="Hello", punctuation="!"):
"""Greet a user with customizable greeting."""
return f"{greeting}, {name}{punctuation}"
print("=== Default Parameters ===")
# Using default parameters
print(greet_user("Alice")) # Uses default greeting and punctuation
print(greet_user("Bob", "Hi")) # Uses default punctuation
print(greet_user("Charlie", "Good morning", ".")) # All custom
# Default parameters with mutable objects (be careful!)
def add_item(item, items_list=None):
"""Add item to list, creating new list if none provided."""
if items_list is None:
items_list = [] # Create new list each time
items_list.append(item)
return items_list
# This works correctly
list1 = add_item("apple")
list2 = add_item("banana")
print(f"List1: {list1}") # ['apple']
print(f"List2: {list2}") # ['banana']
# Keyword-only arguments (Python 3+)
def create_profile(name, *, age, city):
"""Create profile with keyword-only arguments after *."""
return {"name": name, "age": age, "city": city}
# This works
profile = create_profile("Alice", age=25, city="New York")
print(f"Profile: {profile}")
# This would raise an error
# profile = create_profile("Alice", 25, "New York") # TypeError
# Keyword Arguments
def calculate_compound_interest(principal, rate, time, compound_frequency=12):
"""Calculate compound interest with customizable frequency."""
amount = principal * (1 + rate/compound_frequency) ** (compound_frequency * time)
return amount - principal
print("\n=== Keyword Arguments ===")
# Using keyword arguments for clarity
interest1 = calculate_compound_interest(
principal=1000,
rate=0.05,
time=2,
compound_frequency=12
)
interest2 = calculate_compound_interest(
principal=1000,
rate=0.05,
time=2,
compound_frequency=4 # Quarterly compounding
)
print(f"Monthly compounding: ${interest1:.2f}")
print(f"Quarterly compounding: ${interest2:.2f}")
# *args (Arbitrary Positional Arguments)
def calculate_statistics(*args):
"""Calculate basic statistics for any number of values."""
if not args:
return "No values provided"
total = sum(args)
count = len(args)
average = total / count
minimum = min(args)
maximum = max(args)
return {
"count": count,
"total": total,
"average": average,
"minimum": minimum,
"maximum": maximum
}
print("\n=== *args ===")
# Using *args
stats1 = calculate_statistics(1, 2, 3, 4, 5)
stats2 = calculate_statistics(10, 20, 30)
stats3 = calculate_statistics() # Edge case
print(f"Stats 1: {stats1}")
print(f"Stats 2: {stats2}")
print(f"Stats 3: {stats3}")
# Unpacking with *args
def multiply_all(*args):
"""Multiply all provided numbers."""
result = 1
for num in args:
result *= num
return result
numbers = [2, 3, 4, 5]
result = multiply_all(*numbers) # Unpacking the list
print(f"Multiply all result: {result}")
# Another practical example
def format_report(title, *data_points):
"""Format a report with title and variable data points."""
report = f"=== {title} ===\n"
for i, point in enumerate(data_points, 1):
report += f"{i}. {point}\n"
return report
report = format_report("Sales Report", "Q1: $100K", "Q2: $120K", "Q3: $95K")
print(report)
# **kwargs (Arbitrary Keyword Arguments)
def create_database_record(table_name, **kwargs):
"""Create a database record with flexible fields."""
record = {
"table": table_name,
"fields": kwargs,
"created_at": "2024-01-01" # Example timestamp
}
return record
print("\n=== **kwargs ===")
# Using **kwargs
user_record = create_database_record(
"users",
id=1,
name="Alice",
email="alice@example.com",
age=25
)
product_record = create_database_record(
"products",
id=101,
name="Laptop",
price=999.99,
category="Electronics",
in_stock=True
)
print(f"User record: {user_record}")
print(f"Product record: {product_record}")
# Unpacking dictionaries with **kwargs
def update_user_profile(**kwargs):
"""Update user profile with provided fields."""
profile = {"name": "Unknown", "age": 0, "city": "Unknown"}
profile.update(kwargs) # Update with provided values
return profile
existing_data = {"name": "Bob", "city": "New York"}
updated_profile = update_user_profile(**existing_data, age=30)
print(f"Updated profile: {updated_profile}")
# Combining *args and **kwargs
def flexible_function(required_arg, *args, **kwargs):
"""Function that accepts required, positional, and keyword arguments."""
print(f"Required argument: {required_arg}")
print(f"Positional arguments (*args): {args}")
print(f"Keyword arguments (**kwargs): {kwargs}")
return {
"required": required_arg,
"positional": args,
"keyword": kwargs
}
print("\n=== Combining *args and **kwargs ===")
# Using all types of arguments
result = flexible_function(
"Hello", # required
1, 2, 3, # *args
name="Alice", age=25 # **kwargs
)
print(f"Function result: {result}")
# Practical example: Database query builder
def build_query(operation, table, *conditions, **options):
"""Build a database query with flexible parameters."""
query = f"{operation.upper()} FROM {table}"
if conditions:
query += " WHERE " + " AND ".join(conditions)
if options:
if 'order_by' in options:
query += f" ORDER BY {options['order_by']}"
if 'limit' in options:
query += f" LIMIT {options['limit']}"
return query
# Example queries
query1 = build_query(
"SELECT", "users",
"age > 18", "status = 'active'",
order_by="name", limit=10
)
query2 = build_query(
"DELETE", "products",
"category = 'discontinued'",
"stock = 0"
)
print(f"Query 1: {query1}")
print(f"Query 2: {query2}")
# Lambda Functions
print("\n=== Lambda Functions ===")
# Basic lambda functions
square = lambda x: x ** 2
add = lambda x, y: x + y
is_even = lambda x: x % 2 == 0
print(f"Square of 5: {square(5)}")
print(f"Add 3 and 4: {add(3, 4)}")
print(f"Is 6 even? {is_even(6)}")
# Lambda with multiple statements (using tuples)
process = lambda x: (x * 2, x ** 2, x + 1)
result = process(5)
print(f"Process result: {result}")
# Using lambda with map()
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x ** 2, numbers))
doubles = list(map(lambda x: x * 2, numbers))
print(f"Squares: {squares}")
print(f"Doubles: {doubles}")
# Using lambda with filter()
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
large_numbers = list(filter(lambda x: x > 3, numbers))
print(f"Even numbers: {even_numbers}")
print(f"Numbers > 3: {large_numbers}")
# Using lambda with sorted()
students = [
{"name": "Alice", "grade": 85, "age": 20},
{"name": "Bob", "grade": 92, "age": 19},
{"name": "Charlie", "grade": 78, "age": 21}
]
# Sort by grade (descending)
by_grade = sorted(students, key=lambda s: s["grade"], reverse=True)
print("Sorted by grade:", by_grade)
# Sort by age (ascending)
by_age = sorted(students, key=lambda s: s["age"])
print("Sorted by age:", by_age)
# Using lambda with reduce()
from functools import reduce
product = reduce(lambda x, y: x * y, numbers)
print(f"Product of all numbers: {product}")
# Complex lambda example
texts = ["hello world", "python programming", "data science"]
word_counts = list(map(lambda text: len(text.split()), texts))
print(f"Word counts: {word_counts}")
# Recursion
print("\n=== Recursion ===")
def factorial(n):
"""Calculate factorial using recursion."""
# Base case
if n <= 1:
return 1
# Recursive case
return n * factorial(n - 1)
# Test factorial
for i in range(1, 6):
print(f"{i}! = {factorial(i)}")
def fibonacci(n):
"""Calculate nth Fibonacci number using recursion."""
# Base cases
if n <= 0:
return 0
elif n == 1:
return 1
# Recursive case
return fibonacci(n - 1) + fibonacci(n - 2)
# Test fibonacci (note: this is inefficient for large n)
for i in range(10):
print(f"fibonacci({i}) = {fibonacci(i)}")
# More efficient recursive fibonacci with memoization
def fibonacci_memo(n, memo={}):
"""Calculate nth Fibonacci number with memoization."""
if n in memo:
return memo[n]
if n <= 0:
return 0
elif n == 1:
return 1
memo[n] = fibonacci_memo(n - 1, memo) + fibonacci_memo(n - 2, memo)
return memo[n]
# Test memoized fibonacci
print(f"fibonacci_memo(40) = {fibonacci_memo(40)}")
# Practical Recursion Examples
def binary_search(arr, target, left=0, right=None):
"""Binary search using recursion."""
if right is None:
right = len(arr) - 1
# Base case
if left > right:
return -1
# Calculate middle index
mid = (left + right) // 2
# Base case: found target
if arr[mid] == target:
return mid
# Recursive cases
elif arr[mid] > target:
return binary_search(arr, target, left, mid - 1)
else:
return binary_search(arr, target, mid + 1, right)
# Test binary search
sorted_numbers = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
target = 7
result = binary_search(sorted_numbers, target)
print(f"Binary search for {target}: index {result}")
def tower_of_hanoi(n, source, destination, auxiliary):
"""Solve Tower of Hanoi puzzle using recursion."""
if n == 1:
print(f"Move disk 1 from {source} to {destination}")
return
tower_of_hanoi(n - 1, source, auxiliary, destination)
print(f"Move disk {n} from {source} to {destination}")
tower_of_hanoi(n - 1, auxiliary, destination, source)
# Test Tower of Hanoi
print("Tower of Hanoi solution for 3 disks:")
tower_of_hanoi(3, "A", "C", "B")
def flatten_list(nested_list):
"""Flatten a nested list using recursion."""
result = []
for item in nested_list:
if isinstance(item, list):
result.extend(flatten_list(item))
else:
result.append(item)
return result
# Test flattening
nested = [1, [2, 3], [4, [5, 6]], 7]
flattened = flatten_list(nested)
print(f"Nested: {nested}")
print(f"Flattened: {flattened}")
# Function Decorators
print("\n=== Function Decorators ===")
def timer_decorator(func):
"""Decorator to measure function execution time."""
import time
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time:.4f} seconds")
return result
return wrapper
# Using the decorator
@timer_decorator
def slow_function():
"""A function that takes some time to execute."""
import time
time.sleep(0.1) # Simulate work
return "Done"
result = slow_function()
print(f"Result: {result}")
def retry_decorator(max_attempts=3):
"""Decorator to retry function on failure."""
def decorator(func):
def wrapper(*args, **kwargs):
last_exception = None
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
last_exception = e
print(f"Attempt {attempt + 1} failed: {e}")
if attempt < max_attempts - 1:
print("Retrying...")
print(f"All {max_attempts} attempts failed")
raise last_exception
return wrapper
return decorator
# Using the retry decorator
@retry_decorator(max_attempts=3)
def unreliable_function():
"""A function that sometimes fails."""
import random
if random.random() < 0.7: # 70% chance of failure
raise ValueError("Random failure")
return "Success!"
try:
result = unreliable_function()
print(f"Result: {result}")
except ValueError as e:
print(f"Final error: {e}")
def cache_decorator(func):
"""Decorator to cache function results."""
cache = {}
def wrapper(*args, **kwargs):
# Create cache key
key = str(args) + str(sorted(kwargs.items()))
if key in cache:
print(f"Cache hit for {func.__name__}")
return cache[key]
print(f"Cache miss for {func.__name__}")
result = func(*args, **kwargs)
cache[key] = result
return result
return wrapper
# Using cache decorator
@cache_decorator
def expensive_calculation(n):
"""Simulate an expensive calculation."""
import time
time.sleep(0.1) # Simulate work
return n ** 2
# First call (cache miss)
result1 = expensive_calculation(5)
print(f"Result 1: {result1}")
# Second call (cache hit)
result2 = expensive_calculation(5)
print(f"Result 2: {result2}")
def validation_decorator(validate_func):
"""Decorator for input validation."""
def decorator(func):
def wrapper(*args, **kwargs):
# Validate inputs
if not validate_func(*args, **kwargs):
raise ValueError("Input validation failed")
return func(*args, **kwargs)
return wrapper
return decorator
# Validation function
def validate_positive_numbers(*args, **kwargs):
"""Validate that all numeric arguments are positive."""
for arg in args:
if isinstance(arg, (int, float)) and arg <= 0:
return False
for value in kwargs.values():
if isinstance(value, (int, float)) and value <= 0:
return False
return True
# Using validation decorator
@validation_decorator(validate_positive_numbers)
def divide_positive_numbers(a, b):
"""Divide two positive numbers."""
return a / b
# This will work
try:
result = divide_positive_numbers(10, 2)
print(f"Division result: {result}")
except ValueError as e:
print(f"Error: {e}")
# This will fail validation
try:
result = divide_positive_numbers(-5, 2)
print(f"Division result: {result}")
except ValueError as e:
print(f"Error: {e}")
# Practical Examples
print("\n=== Practical Examples ===")
# Example 1: Data Processing Pipeline
def data_processing_pipeline():
"""A flexible data processing pipeline using advanced functions."""
def process_numbers(*args, operation="sum", **options):
"""Process numbers with various operations."""
if not args:
return "No numbers provided"
numbers = list(args)
# Apply filters if specified
if 'min_value' in options:
numbers = [n for n in numbers if n >= options['min_value']]
if 'max_value' in options:
numbers = [n for n in numbers if n <= options['max_value']]
# Apply operation
if operation == "sum":
result = sum(numbers)
elif operation == "product":
result = 1
for n in numbers:
result *= n
elif operation == "average":
result = sum(numbers) / len(numbers)
elif operation == "max":
result = max(numbers)
elif operation == "min":
result = min(numbers)
else:
return f"Unknown operation: {operation}"
# Apply transformations if specified
if 'round_to' in options:
result = round(result, options['round_to'])
return result
# Test the pipeline
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Basic operations
print(f"Sum: {process_numbers(*numbers, operation='sum')}")
print(f"Average: {process_numbers(*numbers, operation='average')}")
print(f"Product: {process_numbers(*numbers, operation='product')}")
# With filters
print(f"Sum of numbers >= 5: {process_numbers(*numbers, operation='sum', min_value=5)}")
print(f"Average of numbers <= 7: {process_numbers(*numbers, operation='average', max_value=7)}")
# With rounding
print(f"Average rounded to 2 decimal places: {process_numbers(*numbers, operation='average', round_to=2)}")
# Run the example
data_processing_pipeline()
# Example 2: Function Composition and Higher-Order Functions
def function_composition_examples():
"""Examples of function composition and higher-order functions."""
def compose(f, g):
"""Compose two functions: compose(f, g)(x) = f(g(x))"""
return lambda x: f(g(x))
def pipe(*functions):
"""Pipe data through multiple functions."""
def apply_functions(x):
result = x
for func in functions:
result = func(result)
return result
return apply_functions
# Define some simple functions
add_one = lambda x: x + 1
multiply_by_two = lambda x: x * 2
square = lambda x: x ** 2
# Compose functions
add_one_then_square = compose(square, add_one)
square_then_add_one = compose(add_one, square)
print(f"add_one_then_square(3): {add_one_then_square(3)}") # (3+1)² = 16
print(f"square_then_add_one(3): {square_then_add_one(3)}") # 3²+1 = 10
# Pipe functions
process = pipe(add_one, multiply_by_two, square)
result = process(3) # ((3+1)*2)² = 64
print(f"Pipe result: {result}")
# Higher-order function for creating transformers
def create_transformer(*operations):
"""Create a transformer function from a list of operations."""
def transform(data):
if isinstance(data, (list, tuple)):
return [apply_operations(item) for item in data]
else:
return apply_operations(data)
def apply_operations(x):
result = x
for operation in operations:
result = operation(result)
return result
return transform
# Create specific transformers
number_transformer = create_transformer(lambda x: x + 1, lambda x: x * 2)
string_transformer = create_transformer(str.upper, lambda x: x + "!")
# Test transformers
numbers = [1, 2, 3, 4, 5]
transformed_numbers = number_transformer(numbers)
print(f"Transformed numbers: {transformed_numbers}")
words = ["hello", "world", "python"]
transformed_words = string_transformer(words)
print(f"Transformed words: {transformed_words}")
# Run the example
function_composition_examples()
print("\n=== Advanced Functions Examples Complete ===")
相關文章
01_getting_started.py
01_getting_started.py — python source code from the Python learning materials (Python/01_beginner_level/01_getting_started.py).
閱讀文章 →02_core_syntax.py
02_core_syntax.py — python source code from the Python learning materials (Python/01_beginner_level/02_core_syntax.py).
閱讀文章 →03_control_flow.py
03_control_flow.py — python source code from the Python learning materials (Python/01_beginner_level/03_control_flow.py).
閱讀文章 →04_data_structures.py
04_data_structures.py — python source code from the Python learning materials (Python/01_beginner_level/04_data_structures.py).
閱讀文章 →05_functions.py
05_functions.py — python source code from the Python learning materials (Python/01_beginner_level/05_functions.py).
閱讀文章 →06_error_handling.py
06_error_handling.py — python source code from the Python learning materials (Python/01_beginner_level/06_error_handling.py).
閱讀文章 →