Introdução
Os argumentos de função em Python são um aspecto fundamental da programação, mas lidar com argumentos ausentes ou inválidos pode ser desafiador. Este tutorial irá guiá-lo através do tratamento de argumentos de função em Python, desde a compreensão dos conceitos básicos até a implementação de estratégias robustas de validação e tratamento de erros. Ao final, você será capaz de escrever código Python que gerencia elegantemente os argumentos de função, levando a aplicações mais confiáveis e sustentáveis.
Compreendendo os Argumentos Básicos de Função e Valores Padrão
Em Python, as funções são blocos de código reutilizáveis que executam tarefas específicas. Ao definir uma função, você pode especificar parâmetros que a função espera receber. Vamos aprender como configurar funções com diferentes tipos de argumentos e explorar como fornecer valores padrão.
Criando Nossa Primeira Função
Vamos começar criando um arquivo Python simples para trabalhar. No WebIDE, navegue até o diretório do projeto e crie um novo arquivo chamado function_args.py:
- Clique no menu "File" no WebIDE
- Selecione "New File"
- Insira
function_args.pycomo o nome do arquivo - Clique em "OK"
Agora, vamos adicionar uma função básica a este arquivo:
def greet(name):
"""A simple function that greets a person by name."""
return f"Hello, {name}!"
## Call the function and print the result
result = greet("Alice")
print(result)
Salve o arquivo (Ctrl+S ou File > Save) e execute-o no terminal:
python3 function_args.py
Você deve ver a saída:
Hello, Alice!
Compreendendo os Argumentos Obrigatórios
No exemplo acima, name é um argumento obrigatório. Se você tentar chamar a função sem fornecer este argumento, o Python irá levantar um erro.
Vamos modificar nosso arquivo para demonstrar isso:
def greet(name):
"""A simple function that greets a person by name."""
return f"Hello, {name}!"
## This will work
result = greet("Alice")
print(result)
## This will raise an error
try:
result = greet()
print(result)
except TypeError as e:
print(f"Error: {e}")
Salve o arquivo e execute-o:
python3 function_args.py
Saída:
Hello, Alice!
Error: greet() missing 1 required positional argument: 'name'
Como você pode ver, o Python levanta um TypeError quando não fornecemos o argumento obrigatório.
Adicionando Valores Padrão
Para tornar os argumentos opcionais, podemos fornecer valores padrão. Vamos atualizar nossa função:
def greet(name="Guest"):
"""A function that greets a person by name, with a default value."""
return f"Hello, {name}!"
## With an argument
result1 = greet("Alice")
print(result1)
## Without an argument - uses the default value
result2 = greet()
print(result2)
Salve e execute:
python3 function_args.py
Saída:
Hello, Alice!
Hello, Guest!
Agora a função funciona com e sem um argumento.
Múltiplos Argumentos com Padrões
Vamos expandir nossa função para lidar com múltiplos argumentos, alguns com valores padrão:
def greet(name="Guest", message="Hello", punctuation="!"):
"""A function with multiple arguments and default values."""
return f"{message}, {name}{punctuation}"
## Using all default values
print(greet())
## Providing only the name
print(greet("Alice"))
## Providing name and message
print(greet("Bob", "Hi"))
## Providing all arguments
print(greet("Charlie", "Welcome", "!!!"))
Salve e execute:
python3 function_args.py
Saída:
Hello, Guest!
Hello, Alice!
Hi, Bob!
Welcome, Charlie!!!
Usando Argumentos de Palavra-chave (Keyword Arguments)
Você também pode especificar argumentos por nome, independentemente de sua ordem:
def greet(name="Guest", message="Hello", punctuation="!"):
"""A function with multiple arguments and default values."""
return f"{message}, {name}{punctuation}"
## Using keyword arguments
print(greet(message="Hey", name="David"))
print(greet(punctuation="...", message="Welcome back", name="Emma"))
Salve e execute:
python3 function_args.py
Saída:
Hey, David!
Welcome back, Emma...
Isso é particularmente útil quando uma função tem muitos argumentos e você só quer especificar alguns deles.
Agora você entende como criar funções com argumentos padrão e como usar argumentos de palavra-chave. No próximo passo, exploraremos maneiras mais avançadas de lidar com argumentos de função ausentes ou inválidos.
Lidando com Argumentos Ausentes com *args e **kwargs
Em Python, às vezes precisamos criar funções flexíveis que podem aceitar um número variável de argumentos. Para lidar com esses casos, o Python fornece dois elementos de sintaxe especiais: *args e **kwargs.
Criando um Novo Arquivo Python
Vamos criar um novo arquivo para trabalhar com esses conceitos:
- Clique no menu "File" no WebIDE
- Selecione "New File"
- Insira
flexible_args.pycomo o nome do arquivo - Clique em "OK"
Compreendendo *args
A sintaxe *args permite que uma função aceite qualquer número de argumentos posicionais, que são coletados em uma tupla.
Adicione o seguinte código a flexible_args.py:
def sum_numbers(*args):
"""A function that sums up any number of arguments."""
result = 0
for num in args:
result += num
return result
## Test the function with different numbers of arguments
print(f"Sum of 1, 2: {sum_numbers(1, 2)}")
print(f"Sum of 1, 2, 3, 4, 5: {sum_numbers(1, 2, 3, 4, 5)}")
print(f"No arguments: {sum_numbers()}")
Salve o arquivo e execute-o:
python3 flexible_args.py
Saída:
Sum of 1, 2: 3
Sum of 1, 2, 3, 4, 5: 15
No arguments: 0
Isso demonstra como *args pode lidar com qualquer número de argumentos, incluindo nenhum. Dentro da função, args é uma tupla contendo todos os argumentos fornecidos.
Compreendendo **kwargs
A sintaxe **kwargs permite que uma função aceite qualquer número de argumentos de palavra-chave (keyword arguments), que são coletados em um dicionário.
Vamos adicionar outra função ao nosso arquivo:
def build_profile(**kwargs):
"""A function that builds a user profile from keyword arguments."""
profile = {}
## Add required fields with defaults
profile["name"] = kwargs.get("name", "Anonymous")
profile["age"] = kwargs.get("age", "Not specified")
## Add any additional fields
for key, value in kwargs.items():
if key not in ["name", "age"]:
profile[key] = value
return profile
## Test the function with different keyword arguments
print("Basic profile:", build_profile())
print("Full profile:", build_profile(name="Alice", age=30, occupation="Developer", location="New York"))
print("Custom fields:", build_profile(hobby="Reading", favorite_color="Blue"))
Salve e execute:
python3 flexible_args.py
Saída:
Basic profile: {'name': 'Anonymous', 'age': 'Not specified'}
Full profile: {'name': 'Alice', 'age': 30, 'occupation': 'Developer', 'location': 'New York'}
Custom fields: {'name': 'Anonymous', 'age': 'Not specified', 'hobby': 'Reading', 'favorite_color': 'Blue'}
Observe como kwargs.get("key", default_value) nos permite recuperar valores com padrões se eles não existirem.
Combinando Required, Default, *args e **kwargs
Vamos criar uma função mais complexa que combina todos esses tipos de argumentos:
def format_message(recipient, message="Hello", *args, **kwargs):
"""
A function that formats a message with various customization options.
- recipient: Required - who the message is for
- message: Default greeting
- *args: Additional message parts
- **kwargs: Formatting options
"""
## Start with the basic message
full_message = f"{message}, {recipient}!"
## Add any additional message parts
if args:
full_message += " " + " ".join(args)
## Apply formatting options
if kwargs.get("upper", False):
full_message = full_message.upper()
if kwargs.get("wrap", False):
full_message = f"[{full_message}]"
return full_message
## Test with different combinations
print(format_message("Alice"))
print(format_message("Bob", "Hi"))
print(format_message("Charlie", "Welcome", "Hope", "you", "are", "well"))
print(format_message("David", "Greetings", upper=True))
print(format_message("Emma", wrap=True))
print(format_message("Frank", "Hey", "How's it going?", upper=True, wrap=True))
Salve e execute:
python3 flexible_args.py
Saída:
Hello, Alice!
Hi, Bob!
Welcome, Charlie! Hope you are well
GREETINGS, DAVID!
[Hello, Emma!]
[HEY, FRANK! HOW'S IT GOING?]
Este exemplo demonstra como usar todos os tipos de argumentos de função juntos:
recipienté um argumento posicional obrigatóriomessagetem um valor padrão, tornando-o opcional*argscaptura quaisquer argumentos posicionais adicionais**kwargscaptura quaisquer argumentos de palavra-chave
Ao combinar essas abordagens, você pode criar funções altamente flexíveis que lidam com argumentos ausentes ou opcionais de forma elegante.
Validando Argumentos de Função
Ao criar funções em Python, é importante verificar se os argumentos passados para suas funções são válidos antes de prosseguir com a lógica principal da função. Nesta etapa, aprenderemos várias técnicas para validar argumentos de função.
Criando um Novo Arquivo Python
Vamos criar um novo arquivo para trabalhar com conceitos de validação:
- Clique no menu "File" no WebIDE
- Selecione "New File"
- Insira
validate_args.pycomo o nome do arquivo - Clique em "OK"
Validação Básica com Condicionais
A maneira mais simples de validar argumentos é usar instruções condicionais. Vamos começar com algumas validações básicas:
def calculate_rectangle_area(length, width):
"""Calculate the area of a rectangle, validating inputs."""
## Validate that inputs are numbers
if not isinstance(length, (int, float)):
raise TypeError("Length must be a number")
if not isinstance(width, (int, float)):
raise TypeError("Width must be a number")
## Validate that inputs are positive
if length <= 0:
raise ValueError("Length must be positive")
if width <= 0:
raise ValueError("Width must be positive")
## Calculate the area
return length * width
## Test with valid inputs
try:
area = calculate_rectangle_area(5, 3)
print(f"Area of rectangle: {area}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
## Test with invalid types
try:
area = calculate_rectangle_area("5", 3)
print(f"Area of rectangle: {area}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
## Test with invalid values
try:
area = calculate_rectangle_area(5, -3)
print(f"Area of rectangle: {area}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
Salve e execute:
python3 validate_args.py
Saída:
Area of rectangle: 15
Error: Length must be a number
Error: Width must be positive
Esta função valida os tipos e os valores de seus argumentos antes de realizar quaisquer cálculos. Quando argumentos inválidos são detectados, mensagens de erro apropriadas são levantadas.
Usando Asserções para Validação
Outra maneira de validar argumentos é usar asserções. Asserções são declarações que levantam um AssertionError se uma condição não for atendida:
def calculate_discount(price, discount_percent):
"""Calculate the discounted price."""
## Assert that inputs are valid
assert isinstance(price, (int, float)), "Price must be a number"
assert isinstance(discount_percent, (int, float)), "Discount must be a number"
assert price >= 0, "Price cannot be negative"
assert 0 <= discount_percent <= 100, "Discount must be between 0 and 100"
## Calculate the discount
discount_amount = price * (discount_percent / 100)
return price - discount_amount
## Test with valid inputs
try:
discounted_price = calculate_discount(100, 20)
print(f"Discounted price: ${discounted_price}")
except AssertionError as e:
print(f"Error: {e}")
## Test with invalid discount percentage
try:
discounted_price = calculate_discount(100, 120)
print(f"Discounted price: ${discounted_price}")
except AssertionError as e:
print(f"Error: {e}")
Salve e execute:
python3 validate_args.py
Saída:
Discounted price: $80.0
Error: Discount must be between 0 and 100
As asserções são úteis para desenvolvimento e depuração, mas podem ser desativadas no código de produção, portanto, nem sempre são a melhor escolha para validação em aplicações do mundo real.
Usando Dicas de Tipo para Documentação
Python 3.5+ suporta dicas de tipo (type hints), que podem ajudar a documentar os tipos esperados de argumentos de função e valores de retorno. Embora as dicas de tipo não realizem validação em tempo de execução por si só, elas fornecem documentação útil e podem ser verificadas por ferramentas externas como mypy:
def calculate_average(numbers: list[float]) -> float:
"""Calculate the average of a list of numbers."""
if not numbers:
raise ValueError("Cannot calculate average of empty list")
if not all(isinstance(n, (int, float)) for n in numbers):
raise TypeError("All elements must be numbers")
return sum(numbers) / len(numbers)
## Test with valid input
try:
avg = calculate_average([1, 2, 3, 4, 5])
print(f"Average: {avg}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
## Test with empty list
try:
avg = calculate_average([])
print(f"Average: {avg}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
## Test with non-numeric elements
try:
avg = calculate_average([1, 2, "3", 4, 5])
print(f"Average: {avg}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
Salve e execute:
python3 validate_args.py
Saída:
Average: 3.0
Error: Cannot calculate average of empty list
Error: All elements must be numbers
Observe que as dicas de tipo (list[float] e -> float) não realizam nenhuma validação por si só - ainda precisamos escrever nosso próprio código de validação. Elas servem como documentação e podem ser verificadas por ferramentas externas.
Criando uma Função Robusta com Validação
Agora, vamos aplicar todas essas técnicas para construir uma função robusta que calcula o custo total de itens com um desconto:
def calculate_total_cost(items=None, tax_rate=0, discount=0):
"""
Calculate the total cost of items with tax and discount.
Args:
items: List of (item_name, price) tuples
tax_rate: Tax rate percentage (0-100)
discount: Discount percentage (0-100)
Returns:
A dictionary with the total, subtotal, tax amount, and discount amount
"""
## Validate items
if items is None:
items = []
if not isinstance(items, list):
raise TypeError("Items must be a list")
## Validate each item in the list
for i, item in enumerate(items):
if not isinstance(item, tuple) or len(item) != 2:
raise ValueError(f"Item {i} must be a tuple of (name, price)")
name, price = item
if not isinstance(name, str):
raise TypeError(f"Name of item {i} must be a string")
if not isinstance(price, (int, float)):
raise TypeError(f"Price of item {i} must be a number")
if price < 0:
raise ValueError(f"Price of item {i} cannot be negative")
## Validate tax_rate and discount
if not isinstance(tax_rate, (int, float)):
raise TypeError("Tax rate must be a number")
if not isinstance(discount, (int, float)):
raise TypeError("Discount must be a number")
if not (0 <= tax_rate <= 100):
raise ValueError("Tax rate must be between 0 and 100")
if not (0 <= discount <= 100):
raise ValueError("Discount must be between 0 and 100")
## Calculate the total
subtotal = sum(price for _, price in items)
discount_amount = subtotal * (discount / 100)
tax_amount = (subtotal - discount_amount) * (tax_rate / 100)
total = subtotal - discount_amount + tax_amount
return {
"subtotal": subtotal,
"discount_amount": discount_amount,
"tax_amount": tax_amount,
"total": total
}
## Test with valid inputs
shopping_cart = [
("Laptop", 1000),
("Mouse", 25),
("Keyboard", 45)
]
try:
result = calculate_total_cost(shopping_cart, tax_rate=8.5, discount=10)
print("Shopping Cart Total:")
for key, value in result.items():
print(f" {key.replace('_', ' ').title()}: ${value:.2f}")
except (TypeError, ValueError) as e:
print(f"Error: {e}")
## Test with invalid item
try:
invalid_cart = [
("Laptop", 1000),
("Mouse", "twenty-five"), ## Invalid price
("Keyboard", 45)
]
result = calculate_total_cost(invalid_cart)
print(result)
except (TypeError, ValueError) as e:
print(f"Error with invalid item: {e}")
Salve e execute:
python3 validate_args.py
Saída:
Shopping Cart Total:
Subtotal: $1070.00
Discount Amount: $107.00
Tax Amount: $81.86
Total: $1044.86
Error with invalid item: Price of item 1 must be a number
Esta função demonstra uma validação robusta por:
- Verificando os tipos de todas as entradas
- Validando a faixa de valores numéricos
- Fornecendo mensagens de erro detalhadas
- Definindo padrões razoáveis para parâmetros opcionais
- Usando docstrings para documentar as entradas e valores de retorno esperados
Ao implementar uma validação completa em suas funções, você pode evitar erros, fornecer um feedback melhor aos usuários e tornar seu código mais robusto e sustentável.
Construindo uma Aplicação Completa
Agora que aprendemos várias técnicas para lidar e validar argumentos de função, vamos aplicar essas habilidades para construir uma aplicação simples, mas completa. Criaremos um sistema básico de rastreamento de despesas que demonstra boas práticas para o tratamento de argumentos de função.
Criando o Arquivo da Aplicação
Vamos criar um novo arquivo Python para nosso rastreador de despesas:
- Clique no menu "File" no WebIDE
- Selecione "New File"
- Insira
expense_tracker.pycomo o nome do arquivo - Clique em "OK"
Projetando as Funções do Rastreamento de Despesas
Nosso rastreador de despesas terá várias funções que lidam com diferentes aspectos do gerenciamento de despesas:
def create_expense(description, amount, category=None, date=None):
"""
Create a new expense entry.
Args:
description (str): Description of the expense
amount (float): The amount spent
category (str, optional): Category of the expense
date (str, optional): The date in YYYY-MM-DD format
Returns:
dict: An expense entry
"""
## Validate description
if not isinstance(description, str):
raise TypeError("Description must be a string")
if not description:
raise ValueError("Description cannot be empty")
## Validate amount
if not isinstance(amount, (int, float)):
raise TypeError("Amount must be a number")
if amount <= 0:
raise ValueError("Amount must be positive")
## Create the expense dictionary
expense = {
"description": description,
"amount": float(amount),
"category": category or "Uncategorized",
"date": date or "Not specified"
}
return expense
def add_expense_to_list(expenses, **kwargs):
"""
Add a new expense to the expenses list.
Args:
expenses (list): The list of expenses
**kwargs: The expense details to be passed to create_expense
Returns:
list: The updated list of expenses
"""
## Validate the expenses list
if not isinstance(expenses, list):
raise TypeError("Expenses must be a list")
## Extract required arguments
if "description" not in kwargs:
raise ValueError("Expense description is required")
if "amount" not in kwargs:
raise ValueError("Expense amount is required")
## Create the expense and add it to the list
expense = create_expense(
kwargs["description"],
kwargs["amount"],
kwargs.get("category"),
kwargs.get("date")
)
expenses.append(expense)
return expenses
def get_total_expenses(expenses, category=None):
"""
Calculate the total amount of expenses, optionally filtered by category.
Args:
expenses (list): The list of expenses
category (str, optional): Filter by this category if provided
Returns:
float: The total amount
"""
## Validate the expenses list
if not isinstance(expenses, list):
raise TypeError("Expenses must be a list")
## Calculate the total
if category:
return sum(e["amount"] for e in expenses if e["category"] == category)
else:
return sum(e["amount"] for e in expenses)
def get_expense_summary(expenses):
"""
Get a summary of expenses by category.
Args:
expenses (list): The list of expenses
Returns:
dict: A dictionary with categories as keys and total amounts as values
"""
## Validate the expenses list
if not isinstance(expenses, list):
raise TypeError("Expenses must be a list")
## Create the summary
summary = {}
for expense in expenses:
category = expense["category"]
if category in summary:
summary[category] += expense["amount"]
else:
summary[category] = expense["amount"]
return summary
Usando Nosso Rastreamento de Despesas
Agora, vamos usar nossas funções para rastrear algumas despesas:
def print_expense_summary(summary):
"""Print a formatted summary of expenses by category."""
print("\nExpense Summary by Category:")
print("-" * 30)
for category, amount in summary.items():
print(f"{category}: ${amount:.2f}")
print("-" * 30)
print(f"Total: ${sum(summary.values()):.2f}")
## Initialize an empty expenses list
expenses = []
## Add some expenses
try:
## Add with required arguments only
expenses = add_expense_to_list(
expenses,
description="Groceries",
amount=45.75
)
## Add with all arguments
expenses = add_expense_to_list(
expenses,
description="Movie tickets",
amount=25.00,
category="Entertainment",
date="2023-11-15"
)
## Add another expense
expenses = add_expense_to_list(
expenses,
description="Dinner",
amount=65.40,
category="Food",
date="2023-11-14"
)
## Add with default category
expenses = add_expense_to_list(
expenses,
description="Gas",
amount=35.80,
date="2023-11-16"
)
## Display all expenses
print("All Expenses:")
for i, expense in enumerate(expenses, 1):
print(f"{i}. {expense['description']}: ${expense['amount']:.2f} " +
f"({expense['category']}, {expense['date']})")
## Get and display the total
total = get_total_expenses(expenses)
print(f"\nTotal expenses: ${total:.2f}")
## Get and display expenses for a specific category
food_total = get_total_expenses(expenses, "Food")
print(f"Food expenses: ${food_total:.2f}")
## Get and display the summary
summary = get_expense_summary(expenses)
print_expense_summary(summary)
except (TypeError, ValueError) as e:
print(f"Error: {e}")
Vamos também adicionar algum código para demonstrar o tratamento de erros:
## Try some invalid inputs
print("\nTesting error handling:")
try:
## Invalid expense description
expenses = add_expense_to_list(expenses, description="", amount=10)
except ValueError as e:
print(f"Caught error: {e}")
try:
## Invalid expense amount
expenses = add_expense_to_list(expenses, description="Coffee", amount=-5)
except ValueError as e:
print(f"Caught error: {e}")
try:
## Missing required argument
expenses = add_expense_to_list(expenses, description="Coffee")
except ValueError as e:
print(f"Caught error: {e}")
Salve o arquivo e execute:
python3 expense_tracker.py
Saída esperada:
All Expenses:
1. Groceries: $45.75 (Uncategorized, Not specified)
2. Movie tickets: $25.00 (Entertainment, 2023-11-15)
3. Dinner: $65.40 (Food, 2023-11-14)
4. Gas: $35.80 (Uncategorized, 2023-11-16)
Total expenses: $171.95
Food expenses: $65.40
Expense Summary by Category:
------------------------------
Uncategorized: $81.55
Entertainment: $25.00
Food: $65.40
------------------------------
Total: $171.95
Testing error handling:
Caught error: Description cannot be empty
Caught error: Amount must be positive
Caught error: Expense amount is required
Revisão da Aplicação
Nosso rastreador de despesas demonstra vários conceitos importantes:
Validação de argumentos: Cada função valida seus argumentos para garantir que eles atendam aos tipos e restrições esperados.
Valores padrão: Usamos valores padrão para tornar certos argumentos opcionais, como
categoryedate.Argumentos obrigatórios: Para informações essenciais como
descriptioneamount, garantimos que elas sejam fornecidas e válidas.Argumentos de palavra-chave (keyword arguments): A função
add_expense_to_listusa**kwargspara aceitar detalhes de despesas de forma flexível.Tratamento de erros: Usamos exceções apropriadas com mensagens de erro significativas para facilitar a depuração.
Docstrings: Cada função inclui uma docstring que explica sua finalidade, argumentos e valores de retorno.
Ao aplicar essas técnicas, criamos uma aplicação robusta que lida com argumentos de função de maneira confiável e amigável ao usuário. Essa abordagem ajuda a prevenir erros, melhora a capacidade de manutenção do código e fornece feedback claro quando algo dá errado.
Resumo
Neste tutorial, você aprendeu técnicas essenciais para lidar com argumentos de função ausentes ou inválidos em Python:
Entendendo argumentos de função básicos e padrões: Você explorou diferentes tipos de argumentos de função, incluindo argumentos obrigatórios, argumentos opcionais com valores padrão e argumentos de palavra-chave (keyword arguments). Essa base o ajuda a projetar funções que são flexíveis e fáceis de usar.
Lidando com números variáveis de argumentos: Você aprendeu a usar
*argse**kwargspara criar funções que podem aceitar qualquer número de argumentos, tornando suas funções mais adaptáveis a diferentes casos de uso.Validando argumentos de função: Você implementou várias técnicas de validação para garantir que os argumentos atendam aos tipos e restrições esperados, ajudando a prevenir erros e fornecer mensagens de erro claras.
Construindo uma aplicação completa: Você aplicou esses conceitos para construir uma aplicação prática de rastreamento de despesas, demonstrando como o tratamento adequado de argumentos leva a um código robusto e sustentável.
Essas habilidades são fundamentais para escrever código Python confiável. Ao lidar adequadamente com argumentos de função, você pode criar funções que são mais flexíveis, fáceis de usar e menos propensas a erros. À medida que você continua sua jornada em Python, essas técnicas o ajudarão a construir aplicações mais sofisticadas que podem lidar com entradas inesperadas e casos extremos com elegância.



