Revisão de Python
---
id: 67f39e391c9b373069def02c
title: Revisão de Python
challengeType: 31
dashedName: review-python
---
# --description--
Trabalhando com o operador
Trabalhando com as declarações
Trabalhando com a Função
funções
Exemplo do módulo Python
O que é Python?
- Introdução: Python é uma linguagem de programação de uso geral conhecida por sua simplicidade e facilidade de uso. Python é usado em muitos campos como ciência de dados e aprendizado de máquina, desenvolvimento web, scripting e automação, sistemas embarcados e IoT e muito mais.
- Casos de Uso Comuns: Python é usado em ciência de dados, aprendizado de máquina, desenvolvimento web, cibersegurança, automação e microcomputadores como o Raspberry Pi e placas compatíveis com MicroPython.
Python no seu ambiente local
- Instalação: A melhor forma de instalar Python no Windows, Mac e Linux é baixar o instalador no site oficial do Python (
https://www.python.org/). - Terminal: Uma interface baseada em texto que permite interagir com seu computador digitando comandos. Cada sistema operacional vem com um app de terminal padrão. No macOS, você pode usar o app Terminal. No Windows, pode usar o Prompt de Comando ou PowerShell. No Linux, cada ambiente de desktop tem seu próprio app de terminal padrão, como GNOME Terminal ou Konsole.
- IDE: IDE significa ambiente de desenvolvimento integrado e inclui recursos como editor de código, ferramentas de teste, terminal e mais.
- Editores de código e IDEs populares para Python: VS Code, PyCharm e Spyder
- Executando código localmente: Para executar código Python, você tem algumas opções. A primeira é clicar no botão de executar no VS Code, que parece um botão de play localizado no canto superior direito. Isso abrirá um terminal e executará seu script Python lá.
main.py:
python main.py
Você deve executar este comando na pasta onde main.py está salvo. Por exemplo, se main.py estiver dentro de uma pasta chamada python-projects, primeiro use o seguinte no terminal:
cd python-projects
Depois execute:
python main.py
Usando o shell interativo do Python
- Definição: Um shell interativo é um programa que permite digitar comandos um de cada vez e ver os resultados. Abra um app de terminal e digite
pythone pressioneEnter. Isso iniciará um shell interativo do Python. O símbolo>>>significa que o Python está esperando você digitar um comando. Tente imprimir"Hello, world!"no terminal:
print("Hello, world!")
Você deve ver o texto aparecer assim:
>>> print("Hello, world!")
Hello, world!
Depois que o texto é impresso, o Python volta para o seguinte:
>>>
Isso significa que você pode digitar outro comando.
- Ciclo ler, avaliar, imprimir, repetir (REPL): Sempre que você digita comandos, o interpretador lê a entrada, avalia, imprime o resultado e volta para mostrar o
>>>para que você possa digitar mais comandos.
Variáveis
- Declaring Variables: Para declarar uma variável, comece com o nome da variável, seguido do operador de atribuição (
=) e logo depois, do valor. Isto pode ser um número, string, boolean, etc. Aqui estão alguns exemplos:
name = 'John Doe'
age = 25
- Convenções de Nomenclatura para Variáveis: Aqui estão as convenções de nomenclatura que você deve usar para variáveis:
- Nomes de variáveis só podem começar com uma letra ou um underscore (_), não com um número.
- Nomes de variáveis só podem conter caracteres alfanuméricos (a-z, A-Z, 0-9) e underscores (_).
- Nomes de variáveis são sensíveis a maiúsculas e minúsculas —
age,AgeeAGEsão considerados únicos. - Nomes de variáveis não podem ser palavras-chave reservadas do Python, como
if,classoudef. - Nomes de variáveis com múltiplas palavras são separados por underscores. Ex.:
snake_case.
Comments
- Comentários de Linha Única: Esses tipos de comentários devem ser usados para notas curtas que você deseja deixar no seu código.
# This is a single line comment
- Strings de Múltiplas Linhas: Esses tipos de strings podem ser usados para deixar notas maiores ou para comentar seções do código.
"""
This is a multi-line string.
Here is some code commented out.
name = 'John Doe'
age = 25
"""
- Função
print(): Para imprimir dados no console, você pode usar a funçãoprint()assim:
print('Hello world!') # Hello world!
Tipos Comuns de Dados em Python
- Introdução: Python é uma linguagem de tipagem dinâmica como JavaScript, o que significa que você não precisa declarar explicitamente os tipos para variáveis. A linguagem sabe qual é o tipo de uma variável com base no que você atribui à variável.
- Integer: Um número inteiro sem decimais:
my_integer_var = 10
print('Integer:', my_integer_var) # Integer: 10
- Float: Um número com decimais:
my_float_var = 4.50
print('Float:', my_float_var) # Float: 4.5
- String: Uma sequência de caracteres envolvida por aspas:
my_string_var = 'hello'
print('String:', my_string_var) # String: hello
- Booleano: Um valor que representa
TrueouFalse:
my_boolean_var = True
print('Boolean:', my_boolean_var) # Boolean: True
- Set: Uma coleção não ordenada de elementos únicos:
my_set_var = {7, 5, 8}
print('Set:', my_set_var) # Set: {7, 5, 8}
- Dicionário: Uma coleção de pares chave-valor, delimitada por chaves:
my_dictionary_var = {"name": "Alice", "age": 25}
print('Dictionary:', my_dictionary_var) # Dictionary: {'name': 'Alice', 'age': 25}
- Tuple: Uma coleção ordenada imutável, delimitada por parênteses:
my_tuple_var = (7, 5, 8)
print('Tuple:', my_tuple_var) # Tuple: (7, 5, 8)
- Range: Uma sequência de números, frequentemente usada em loops:
my_range_var = range(5)
print(my_range_var) # range(0, 5)
- Lista: Uma coleção ordenada de elementos que suporta diferentes tipos de dados:
my_list = [22, 'Hello world', 3.14, True]
print(my_list) # [22, 'Hello world', 3.14, True]
- None: Um valor especial que representa a ausência de um valor:
my_none_var = None
print('None:', my_none_var) # None: None
Tipos Imutáveis e Mutáveis
- Tipos Imutáveis: Esses tipos não podem mudar depois de declarados, embora você possa apontar suas variáveis para algo novo, o que é chamado de reatribuição. Eles incluem integer, float, complex, boolean, string, tuple, range e
None. - Tipos Mutáveis: Esses tipos podem mudar depois de declarados. Você pode adicionar, remover e atualizar seus itens. Eles incluem tipos de coleção como list, set e dictionary.
- Função
type(): Para ver o tipo de uma variável, você pode usar a funçãotype()assim:
greeting = 'Hello there!'
age = 21
print(type(greeting)) # <class 'str'>
print(type(age)) # <class 'int'>
- Função
isinstance(): Isso é usado para verificar se uma variável corresponde a um tipo de dado específico:
greeting = 'Hello world'
name = 'John Doe'
print(isinstance(greeting, str)) # True
print(isinstance(name, int)) # False
Trabalhando com Strings
- Definição: Como você lembra do Javascript, strings são imutáveis, o que significa que você não pode alterá-las depois que foram criadas. Em Python, você pode usar aspas simples ou aspas duplas. É recomendado escolher uma regra e segui-la:
developer = 'Jessica'
city = "Los Angeles"
- Acessando Caracteres de Strings: Você pode acessar caracteres de strings usando a notação de colchetes assim:
my_str = 'Hello world'
print(my_str[0]) # H
print(my_str[6]) # w
print(my_str[-1]) # d
print(my_str[-2]) # l
- Escapando Strings: Você pode usar uma barra invertida (
\) se sua string contiver aspas assim:
msg = 'It\'s a sunny day'
quote = "She said, \"Hello!\""
- Concatenação de Strings: Para concatenar strings, você pode usar o operador
+assim:
developer = 'Jessica'
print('My name is ' + developer + '.') # My name is Jessica.
Outra forma de concatenar strings é usando o operador +=. Isto é usado para realizar concatenação e atribuição na mesma etapa assim:
greeting = 'My name is '
developer = 'Jessica.'
greeting += developer
print(greeting) # My name is Jessica.
f-strings: Isso é a abreviação de formatted string literals. Permite que você faça interpolação e também alguma concatenação com uma sintaxe compacta e legível:
developer = 'Jessica'
greeting = f'My name is {developer}.'
print(greeting) # My name is Jessica.
- Fatiamento de String: Isso é quando você pode extrair partes de uma string. Aqui está a sintaxe básica:
str[start:stop:step]
A posição inicial representa o índice onde a extração deve começar. A posição final é onde o fatiamento deve terminar. Essa posição não é inclusiva. A posição do passo representa o intervalo para incrementar no fatiamento. Aqui estão alguns exemplos:
message = 'Python is fun!'
print(message[0:6]) # Python
print(message[7:]) # is fun!
print(message[::2]) # Pto sfn
- Obtendo o Comprimento de uma String: A função
len()é usada para retornar o número de caracteres na string:
developer = 'Jessica'
print(len(developer)) # 7
Trabalhando com o operador in
- Operador
in: Isso retorna um booleano que especifica se o caractere ou os caracteres existem na string ou não:
my_str = 'Hello world'
print('Hello' in my_str) # True
print('hey' in my_str) # False
print('hi' in my_str) # False
print('e' in my_str) # True
print('f' in my_str) # False
Métodos Comuns de String
upper(): Este método de string retorna uma nova string com todos os caracteres convertidos para maiúsculas:
developer = 'Jessica'
print(developer.upper()) # JESSICA
lower(): Este método de string retorna uma nova string com todos os caracteres convertidos para minúsculas:
developer = 'Jessica'
print(developer.lower()) # jessica
strip(): Este método de string retorna uma cópia da string com os caracteres especificados no início e no fim removidos (se nenhum argumento for passado para o método, ele remove os espaços em branco no início e no fim).
greeting = ' hello world '
trimmed_my_str = greeting.strip()
print(trimmed_my_str) # 'hello world'
replace(): Isso retorna uma nova string com todas as ocorrências da string antiga substituídas por uma nova.
greeting = 'hello world'
replaced_my_str = greeting.replace('hello', 'hi')
print(replaced_my_str) # 'hi world'
split(): Isso é usado para dividir uma string em uma lista usando um separador especificado. Um separador é uma string que especifica onde a divisão deve acontecer.
dashed_name = 'example-dashed-name'
split_words = dashed_name.split('-')
print(split_words) # ['example', 'dashed', 'name']
join(): Isso é usado para juntar elementos de um iterável em uma string com um separador. Um iterável é uma coleção de elementos que podem ser percorridos como uma lista, string ou uma tupla.
example_list = ['example', 'dashed', 'name']
joined_str = ' '.join(example_list)
print(joined_str) # example dashed name
startswith(prefix): Este método de string retorna um booleano indicando se uma string começa com o prefixo especificado:
developer = 'Naomi'
result = developer.startswith('N')
print(result) # True
endswith(suffix): Este método de string retorna um booleano indicando se uma string termina com o sufixo especificado:
developer = 'Naomi'
result = developer.endswith('N')
print(result) # False
find(): Este método de string retorna o índice da primeira ocorrência de uma substring. Se não for encontrada, então-1é retornado:
developer = 'Naomi'
result = developer.find('N')
print(result) # 0
city = 'Los Angeles'
print(city.find('New')) # -1
count(substring): Este método de string conta quantas vezes uma substring aparece em uma string:
city = 'Los Angeles'
print(city.count('e')) # 2
capitalize(): Este método de string retorna uma nova string com o primeiro caractere em maiúscula e os outros caracteres em minúsculas:
dessert = 'chocolate cake'
print(dessert.capitalize()) # Chocolate cake
isupper(): Este método de string retornaTruese todas as letras na string estiverem em maiúsculas eFalsecaso contrário:
dessert = 'chocolate cake'
print(dessert.isupper()) # False
islower(): Este método de string retornaTruese todas as letras na string estiverem em minúsculas eFalsecaso contrário:
dessert = 'chocolate cake'
print(dessert.islower()) # True
title(): Este método de string retorna uma nova string com a primeira letra de cada palavra em maiúscula:
city = 'los angeles'
print(city.title()) # Los Angeles
maketrans(): Este método de string é usado para criar uma tabela de mapeamentos de caracteres 1 para 1 para tradução. Ele é frequentemente usado com o métodotranslate(), que aplica essa tabela a uma string e retorna o resultado traduzido.
trans_table = str.maketrans('abc', '123')
print(trans_table) # {97: 49, 98: 50, 99: 51}
result = 'abcabc'.translate(trans_table)
print(result) # 123123
Operações Comuns usadas com Integers e Floats
- Operações Matemáticas Básicas: Em Python, você pode fazer operações matemáticas básicas com inteiros e floats incluindo adição, subtração, multiplicação e divisão:
int_1 = 56
int_2 = 12
float_1 = 5.4
float_2 = 12.0
# Addition
print('Integer Addition:', int_1 + int_2) # Integer Addition: 68
print('Float Addition:', float_1 + float_2) # Float Addition: 17.4
# Subtraction
print('Int Subtraction:', int_1 - int_2) # Int Subtraction: 44
print('Float Subtraction:', float_2 - float_1) # Float Subtraction: 6.6
# Multiplication
print('Int Multiplication:', int_1 * int_2) # Int Multiplication: 672
print('Float Multiplication:', float_2 * float_1) # Float Multiplication: 64.80000000000001
# Division
print('Division:', int_1 / int_2) # Division: 4.666666666666667
print('Float Division:', float_2 / float_1) # Float Division: 2.222222222222222
Quando você adiciona um float e um inteiro, o resultado será convertido para um float assim:
int_1 = 56
float_1 = 5.4
print(int_1 + float_1) # 61.4
- Operador Modulo (
%): Isso retorna o resto quando um número é dividido por outro número:
int_1 = 56
int_2 = 12
print(int_1 % int_2) # 8
- Divisão Inteira (
//): Este operador é usado para dividir dois números e arredondar para baixo o resultado para o número inteiro mais próximo:
int_1 = 56
int_2 = 12
print(int_1 // int_2) # 4
- Operador de Exponenciação (
)**: Este operador é usado para elevar um número à potência de outro:
int_1 = 4
int_2 = 2
print(int_1 ** int_2) # 16
- Função
float(): Você pode usar essa função para converter um inteiro em float.
num = 4
print(float(num)) # 4.0
- Função
int(): Você pode usar essa função para converter um float em inteiro.
num = 4.0
print(int(num)) # 4
- Função
round(): Esta é usada para arredondar um número para o inteiro mais próximo:
num_1 = 3.4
num_2 = 7.7
print(round(num_1)) # 3
print(round(num_2)) # 8
- Função
abs(): Esta é usada para retornar o valor absoluto de um número:
num = -13
print(abs(num)) # 13
- Função
pow(): Esta é usada para elevar um número à potência de outro:
result = pow(2, 3)
print(result) # 8
Atribuições aumentadas
- Definição: A atribuição aumentada combina uma operação binária com uma atribuição em um único passo. Ela pega uma variável, aplica uma operação nela com outro valor e armazena o resultado de volta na mesma variável.
# Addition assignment
my_var = 10
my_var += 5
print(my_var) # 15
# Subtraction assignment
count = 14
count -= 3
print(count) # 11
# Multiplication assignment
product = 65
product *= 7
print(product) # 455
# Division assignment
price = 100
price /= 4
print(price) # 25.0
# Floor Division assignment
total_pages = 23
total_pages //= 5
print(total_pages) # 4
# Modulo assignment
bits = 35
bits %= 2
print(bits) # 1
# Exponentiation assignment
power = 2
power **= 3
print(power) # 8
Existem outros operadores de atribuição aumentada também, como aqueles para operadores bit a bit. Eles incluem &=, ^=, >>= e <<=.
Trabalhando com Funções
- Definição: Funções são trechos reutilizáveis de código que recebem entradas (argumentos) e retornam uma saída. Para chamar uma função, você precisa referenciar o nome da função seguido de um conjunto de parênteses:
# Defining a function
def get_sum(num_1, num_2):
return num_1 + num_2
result = get_sum(3, 4) # function call
print(result) # 7
Se uma função não retornar explicitamente um valor, então o valor de retorno padrão é None:
def greet():
print('hello')
result = greet() # hello
print(result) # None
Você também pode fornecer valores padrão para parâmetros assim:
def get_sum(num_1, num_2=2):
return num_1 + num_2
result = get_sum(3)
print(result) # 5
Se você chamar a função sem o número correto de argumentos, você receberá um TypeError:
def calculate_sum(a, b):
print(a + b)
calculate_sum()
# TypeError: calculate_sum() missing 2 required positional arguments: 'a' and 'b'
Funções Internas Comuns
- Função
input(): Esta é usada para solicitar uma entrada do usuário:
name = input('What is your name?') # User types 'Kolade' and presses Enter
print('Hello', name) # Hello Kolade
- Função
int(): Esta é usada para converter um número, booleano ou uma string numérica em um inteiro:
print(int(3.14)) # 3
print(int('42')) # 42
print(int(True)) # 1
print(int(False)) # 0
Escopo em Python
- Escopo Local: Isso ocorre quando uma variável declarada dentro de uma função ou classe só pode ser acessada dentro dessa função ou classe.
def my_func():
num = 10
print(num)
- Escopo Envolvente: Isso ocorre quando uma função que está aninhada dentro de outra função pode acessar as variáveis da função na qual está aninhada.
def outer_func():
msg = 'Hello there!'
def inner_func():
print(msg)
inner_func()
print(outer_func()) # Hello there!
- Escopo Global: Isso se refere a variáveis que são declaradas fora de qualquer função ou classe que podem ser acessadas de qualquer lugar no programa.
tax = 0.70
def get_total(subtotal):
total = subtotal + (subtotal * tax)
return total
print(get_total(100)) # 170.0
- Escopo Embutido: Nomes reservados em Python para funções, módulos, palavras-chave e objetos pré-definidos.
print(str(45)) # '45'
print(type(3.14)) # <class 'float'>
print(isinstance(3, str)) # False
Operadores de comparação
- Igual (
==): Verifica se dois valores são iguais:
print(3 == 4) # False
- Diferente (
!=): Verifica se dois valores não são iguais:
print(3 != 4) # True
- Estritamente maior que (
>): Verifica se um valor é maior que outro:
print(3 > 4) # False
- Estritamente menor que (
<): Verifica se um valor é menor que outro:
print(3 < 4) # True
- Maior ou igual a (
>=): Verifica se um valor é maior ou igual a outro:
print(3 >= 4) # False
- Menor ou igual(
<=): Verifica se um valor é menor ou igual a outro:
print(3 <= 4) # True
Trabalhando com as declarações if, elif e else
- Declarações
if: Estas são condições usadas para determinar se algo é verdadeiro ou não. Se a condição for avaliada comoTrue, então aquele bloco de código será executado.
age = 18
if age >= 18:
print('You are an adult') # You are an adult
- Cláusula
elif: São condições que vêm após uma declaraçãoif. Se a condiçãoeliffor avaliada comoTrue, então aquele bloco de código será executado.
age = 16
if age >= 18:
print('You are an adult')
elif age >= 13:
print('You are a teenager') # You are a teenager
- Cláusula
else: Isso será executado se nenhuma outra condição for avaliada comoTrue.
age = 12
if age >= 18:
print('You are an adult')
elif age >= 13:
print('You are a teenager')
else:
print('You are a child') # You are a child
Você também pode usar declarações if aninhadas assim:
is_citizen = True
age = 25
if is_citizen:
if age >= 18:
print('You are eligible to vote') # You are eligible to vote
else:
print('You are not eligible to vote')
Valores Truthy e Falsy
- Definição: Em Python, todo valor tem um valor booleano inerente, ou um sentido embutido de se ele deve ser tratado como
TrueouFalseem um contexto lógico. Muitos valores são considerados truthy, isto é, eles avaliam paraTrueem um contexto lógico. Outros são falsy, significando que eles avaliam paraFalse. Aqui estão alguns exemplos de valores falsy:
None
False
Integer 0
Float 0.0
Empty strings ''
Outros valores como números diferentes de zero e strings não vazias são truthy.
Trabalhando com a Função bool()
- Definição: Se você quiser verificar se um valor é truthy ou falsy, pode usar a função embutida
bool(). Ela converte explicitamente um valor para seu equivalente booleano e retornaTruepara valores truthy eFalsepara valores falsy. Aqui estão alguns exemplos:
print(bool(False)) # False
print(bool(0)) # False
print(bool('')) # False
print(bool(True)) # True
print(bool(1)) # True
print(bool('Hello')) # True
Operadores booleanos e curto-circuito
- Definição: Estes são operadores especiais que permitem combinar múltiplas expressões para criar uma lógica de tomada de decisão mais complexa no seu código. Existem três operadores Booleanos em Python:
and,orenot. - Operador
and: Este operador recebe dois operandos e retorna o primeiro operando se ele for falso, caso contrário, retorna o segundo operando. Ambos os operandos devem ser verdadeiros para que uma expressão resulte em um valor verdadeiro.
is_citizen = True
age = 25
print(is_citizen and age) # 25
Você também pode usar o operador and em condicionais assim:
is_citizen = True
age = 25
if is_citizen and age >= 18:
print('You are eligible to vote') # You are eligible to vote
else:
print('You are not eligible to vote')
- Operador
or: Este operador retorna o primeiro operando se ele for truthy, caso contrário, retorna o segundo operando. Uma expressãoorresulta em um valor verdadeiro se pelo menos um operando for verdadeiro. Aqui está um exemplo:
age = 19
is_employed = False
print(age or is_employed) # 19
Assim como com o operador and, você pode usar o operador or em condicionais assim:
age = 19
is_student = True
if age < 18 or is_student:
print('You are eligible for a student discount') # You are eligible for a student discount
else:
print('You are not eligible for a student discount')
- Curto-circuito: Os operadores
andeorsão conhecidos como operadores de curto-circuito. Curto-circuito significa que o Python verifica os valores da esquerda para a direita e para assim que determina o resultado final. - Operador
not: Esse operador recebe um único operando e inverte seu valor booleano. Ele converte valores truthy emFalsee valores falsy emTrue. Diferente dos operadores anteriores que vimos,notsempre retornaTrueouFalse. Aqui estão alguns exemplos:
print(not '') # True, because empty string is falsy
print(not 'Hello') # False, because non-empty string is truthy
print(not 0) # True, because 0 is falsy
print(not 1) # False, because 1 is truthy
print(not False) # True, because False is falsy
print(not True) # False, because True is truthy
Aqui está um exemplo do operador not em uma condicional:
is_admin = False
if not is_admin:
print('Access denied for non-administrators.') # Access denied for non-administrators.
else:
print('Welcome, Administrator!')
Listas em Python
- Introdução: Em Python, o tipo de dado lista é uma sequência ordenada de elementos que podem ser compostos por strings, números ou até outras listas. Listas são mutáveis e indexadas de base zero.
cities = ['Los Angeles', 'London', 'Tokyo']
- Acessando elementos em uma lista: Para acessar um elemento da lista
cities, você pode referenciar seu número de índice na sequência:
cities = ['Los Angeles', 'London', 'Tokyo']
cities[0] # Los Angeles
- Acessando elementos usando indexação negativa: Para acessar o último elemento de qualquer lista, você pode usar
-1como número de índice:
cities = ['Los Angeles', 'London', 'Tokyo']
cities[-1] # Tokyo
- A indexação negativa é usada para acessar elementos começando do final da lista em vez do início no índice
0. - Criando listas usando o construtor
list(): Listas também podem ser criadas usando o construtorlist(). O construtorlist()é usado para converter um iterável em uma lista:
developer = 'Jessica'
print(list(developer))
# Result: ['J', 'e', 's', 's', 'i', 'c', 'a']
- Encontrando o comprimento de uma lista: Você pode usar a função
len()para obter o comprimento de uma lista:
numbers = [1, 2, 3, 4, 5]
len(numbers) # 5
- Mutabilidade das listas: Listas são mutáveis, o que significa que você pode atualizar qualquer elemento da lista desde que informe um número de índice válido. Para atualizar listas em um índice específico, você pode atribuir um novo valor a esse índice:
programming_languages = ['Python', 'Java', 'C++', 'Rust']
programming_languages[0] = 'JavaScript'
print(programming_languages) # ['JavaScript', 'Java', 'C++', 'Rust']
- Erro de índice fora do intervalo: Se você informar um índice (positivo ou negativo) que esteja fora dos limites da lista, receberá um
IndexError:
programming_languages = ['Python', 'Java', 'C++', 'Rust']
programming_languages[10] = 'JavaScript'
"""
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
"""
- Removendo elementos de uma lista: Elementos podem ser removidos de uma lista usando a palavra-chave
del:
developer = ['Jane Doe', 23, 'Python Developer']
del developer[1]
print(developer) # ['Jane Doe', 'Python Developer']
- Verificando se um elemento existe em uma lista: A palavra-chave
inpode ser usada para verificar se um elemento existe em uma lista:
programming_languages = ['Python', 'Java', 'C++', 'Rust']
'Rust' in programming_languages # True
'JavaScript' in programming_languages # False
- Aninhando listas: Listas podem ser aninhadas dentro de outras listas:
developer = ['Alice', 25, ['Python', 'Rust', 'C++']]
- Para acessar a lista aninhada, você precisará acessá-la usando o índice
2já que listas são indexadas de base zero.
developer = ['Alice', 25, ['Python', 'Rust', 'C++']]
developer[2] # ['Python', 'Rust', 'C++']
- Para acessar ainda mais a segunda linguagem dessa lista aninhada, você precisará acessá-la usando o índice
1:
developer = ['Alice', 25, ['Python', 'Rust', 'C++']]
developer[2][1] # Rust
- Desempacotando valores de uma lista: Desempacotar valores de uma lista é uma técnica usada para atribuir valores de uma lista a novas variáveis. Aqui está um exemplo para desempacotar a lista
developerem novas variáveis chamadasname,ageejobassim:
developer = ['Alice', 34, 'Rust Developer']
name, age, job = developer
- Se o número de variáveis do lado esquerdo do operador de atribuição não corresponder ao total de itens na lista, você receberá um
ValueError. - Coletando itens restantes de uma lista: Para coletar quaisquer elementos restantes de uma lista, você pode usar o operador asterisco (
*) assim:
developer = ['Alice', 34, 'Rust Developer']
name, *rest = developer
- Fatiando listas: Fatiar é o conceito de acessar uma porção de uma lista usando o operador de fatia
:. Para fatiar uma lista que começa no índice1e termina antes do índice3, você pode usar a seguinte sintaxe:
desserts = ['Cake', 'Cookies', 'Ice Cream', 'Pie']
desserts[1:3] # ['Cookies', 'Ice Cream']
- Intervalos de passo: Também é possível especificar um intervalo de passo que determina quanto incrementar entre os índices. Aqui está um exemplo se você quiser extrair uma lista apenas com números pares usando fatiamento:
numbers = [1, 2, 3, 4, 5, 6]
numbers[1::2] # [2, 4, 6]
Métodos de listas
- append(): usado para adicionar um item ao final da lista. Aqui está um exemplo de uso do método
append()para adicionar o número6a esta listanumbers:
numbers = [1, 2, 3, 4, 5]
numbers.append(6)
print(numbers) # [1, 2, 3, 4, 5, 6]
- adicionando listas: o método
append()também pode ser usado para adicionar uma lista ao final de outra:
numbers = [1, 2, 3, 4, 5]
even_numbers = [6, 8, 10]
numbers.append(even_numbers)
print(numbers) # [1, 2, 3, 4, 5, [6, 8, 10]]
- extend(): usado para adicionar múltiplos itens ao final de uma lista. Aqui está um exemplo de adicionar os números
6,8e10ao final da listanumbers:
numbers = [1, 2, 3, 4, 5]
even_numbers = [6, 8, 10]
numbers.extend(even_numbers)
print(numbers) # [1, 2, 3, 4, 5, 6, 8, 10]
- insert(): usado para inserir um item em um índice específico da lista. Aqui está um exemplo de uso do método
insert():
numbers = [1, 2, 3, 4, 5]
numbers.insert(2, 2.5)
print(numbers) # [1, 2, 2.5, 3, 4, 5]
- remove(): usado para remover um item da lista. O método
remove()removerá apenas a primeira ocorrência de um item na lista:
numbers = [1, 2, 3, 4, 5, 5, 5]
numbers.remove(5)
print(numbers) # [1, 2, 3, 4, 5, 5]
- pop(): usado para remover um item específico da lista e retorná-lo:
numbers = [1, 2, 3, 4, 5]
numbers.pop(1) # The number 2 is returned
- Se você não especificar um elemento para o método
pop, o último elemento será removido.
numbers = [1, 2, 3, 4, 5]
numbers.pop() # The number 5 is returned
- clear(): usado para remover todos os itens da lista:
numbers = [1, 2, 3, 4, 5]
numbers.clear()
print(numbers) # []
- sort(): o método
sort()é usado para ordenar os elementos no local. Aqui está um exemplo de ordenar uma lista aleatória denumbersno local:
numbers = [19, 2, 35, 1, 67, 41]
numbers.sort()
print(numbers) # [1, 2, 19, 35, 41, 67]
- sorted(): uma função embutida que retorna uma nova lista ordenada em vez de modificar a lista original:
numbers = [19, 2, 35, 1, 67, 41]
sorted_numbers = sorted(numbers)
print(sorted_numbers) # [1, 2, 19, 35, 41, 67]
print(numbers) # [19, 2, 35, 1, 67, 41]
- reverse(): usado para inverter a ordem dos elementos em uma lista:
numbers = [6, 5, 4, 3, 2, 1]
numbers.reverse()
print(numbers) # [1, 2, 3, 4, 5, 6]
- index(): usado para buscar o primeiro índice onde um elemento pode ser encontrado em uma lista:
programming_languages = ['Rust', 'Java', 'Python', 'C++']
programming_languages.index('Java') # 1
- Se o elemento não puder ser encontrado usando o método
index(), o resultado será umValueError.
Tuplas em Python
- Definição: Uma tupla é um tipo de dado Python usado para criar uma sequência ordenada de valores. Tuplas podem conter um conjunto misto de tipos de dados:
developer = ('Alice', 34, 'Rust Developer')
- Tuplas são imutáveis, ou seja, os elementos na tupla não podem ser alterados depois de criados. Se você tentar atualizar um dos itens na tupla, receberá um
TypeError:
programming_languages = ('Python', 'Java', 'C++', 'Rust')
programming_languages[0] = 'JavaScript'
"""
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: "tuple" object does not support item assignment
"""
- Acessando elementos de uma tupla: Para acessar um elemento de uma tupla, use a notação por colchetes e o número do índice:
developer = ('Alice', 34, 'Rust Developer')
developer[1] # 34
- Índices negativos podem ser usados para acessar elementos começando pelo final da tupla:
numbers = (1, 2, 3, 4, 5)
numbers[-2] # 4
- Se você tentar passar um número de índice que exceda ou seja igual ao comprimento da tupla, receberá um
IndexError:
numbers = (1, 2, 3, 4, 5)
numbers[7]
"""
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: tuple index out of range
"""
- Uma tupla também pode ser criada usando o construtor
tuple(). Dentro do construtor, você pode passar diferentes iteráveis como strings, listas e até outras tuplas.
developer = 'Jessica'
print(tuple(developer))
# Result: ('J', 'e', 's', 's', 'i', 'c', 'a')
- Verificando itens em uma tupla: Para checar se um item está em uma tupla, você pode usar a palavra-chave
inassim:
programming_languages = ('Python', 'Java', 'C++', 'Rust')
'Rust' in programming_languages # True
'JavaScript' in programming_languages # False
- Desempacotando tuplas: Itens podem ser desempacotados de uma tupla assim:
developer = ('Alice', 34, 'Rust Developer')
name, age, job = developer
- Se precisar coletar os elementos restantes de uma tupla, você pode usar o operador asterisco (
*) assim:
developer = ('Alice', 34, 'Rust Developer')
name, *rest = developer
- Fatiando tuplas: Fatiamento pode ser usado para extrair uma parte de uma tupla. Por exemplo, os itens
pieecookiespodem ser fatiados em uma tupla separada:
desserts = ('cake', 'pie', 'cookies', 'ice cream')
desserts[1:3] # ('pie', 'cookies')
- Removendo itens de tuplas: Remover um item de uma tupla causará um
TypeErrorpois tuplas são imutáveis:
developer = ('Jane Doe', 23, 'Python Developer')
del developer[1]
"""
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: "tuple" object doesn't support item deletion
"""
- Quando usar uma tupla vs uma lista?: Se você precisa de uma coleção dinâmica de elementos onde pode adicionar, remover e atualizar elementos, deve usar uma lista. Se sabe que está trabalhando com uma coleção fixa e imutável de dados, deve usar uma tupla.
Métodos comuns para tuplas
count(): Usado para determinar quantas vezes um item aparece em uma tupla. Por exemplo, você pode verificar quantas vezes a linguagem'Rust'aparece na tupla:
programming_languages = ('Rust', 'Java', 'Python', 'C++', 'Rust')
programming_languages.count('Rust') # 2
- Se o item especificado no método
count()não estiver presente na tupla, o valor de retorno será0:
programming_languages = ('Rust', 'Java', 'Python', 'C++', 'Rust')
programming_languages.count('JavaScript') # 0
- Se nenhum argumento for passado para o método
count(), o Python retornará umTypeError. - index(): Usado para buscar o índice onde um item específico está presente na tupla. Aqui está um exemplo de uso do método
index()para encontrar o índice da linguagem'Java':
programming_languages = ('Rust', 'Java', 'Python', 'C++', 'Rust')
programming_languages.index('Java') # 1
- Se o item especificado não puder ser encontrado, o Python retornará um
ValueError. - Você pode passar um índice inicial opcional para o método
index()para especificar onde começar a busca pelo item na tupla:
programming_languages = ('Rust', 'Java', 'Python', 'C++', 'Rust', 'Python')
programming_languages.index('Python', 3) # 5
- Também é possível passar um índice final opcional para o método
index()para especificar onde parar a busca pelo item na tupla:
programming_languages = ('Rust', 'Java', 'Python', 'C++', 'Rust', 'Python', 'JavaScript', 'Python')
programming_languages.index('Python', 2, 5) # 2
sorted(): Usado para ordenar os elementos de qualquer iterável e retornar uma nova lista ordenada. Aqui está um exemplo de criação de uma nova lista de números usando a funçãosorted():
numbers = (13, 2, 78, 3, 45, 67, 18, 7)
sorted(numbers) # [2, 3, 7, 13, 18, 45, 67, 78]
- Modificando o comportamento da ordenação: Você pode personalizar o comportamento da ordenação para um iterável usando os argumentos opcionais
reverseekey. Aqui está um exemplo de uso do argumentokeypara ordenar itens em uma tupla pelo comprimento:
programming_languages = ('Rust', 'Java', 'Python', 'C++', 'Rust', 'Python')
sorted(programming_languages, key=len)
# Result
# ['C++', 'Rust', 'Java', 'Rust', 'Python', 'Python']
- Você pode criar uma nova lista de valores em ordem reversa, usando o argumento
reverseassim:
programming_languages = ('Rust', 'Java', 'Python', 'C++', 'Rust', 'Python')
print(sorted(programming_languages, reverse=True))
# Result
# ['Rust', 'Rust', 'Python', 'Python', 'Java', 'C++']
Loops em Python
- Definição: Loops são usados para repetir um bloco de código por um número determinado de vezes.
- Loop
for: Usado para iterar sobre uma sequência (como uma lista, tupla ou string) e executar um bloco de código para cada item nessa sequência. Aqui está um exemplo de uso de um loopforpara iterar através de uma lista e imprimir cada linguagem no console:
programming_languages = ['Rust', 'Java', 'Python', 'C++']
for language in programming_languages:
print(language)
"""
Result
Rust
Java
Python
C++
"""
- Aqui está um exemplo de uso de um loop
forpara iterar através da stringcodee imprimir cada caractere:
for char in 'code':
print(char)
"""
Result
c
o
d
e
"""
- Loops
forpodem ser aninhados. Aqui está um exemplo de uso de um loopforaninhado:
categories = ['Fruit', 'Vegetable']
foods = ['Apple', 'Carrot', 'Banana']
for category in categories:
for food in foods:
print(category, food)
"""
Result
Fruit Apple
Fruit Carrot
Fruit Banana
Vegetable Apple
Vegetable Carrot
Vegetable Banana
"""
- Loop
while: Repete um bloco de código até que a condição sejaFalse. Aqui está um exemplo de uso de um loopwhilepara um jogo de adivinhação:
secret_number = 3
guess = 0
while guess != secret_number:
guess = int(input('Guess the number (1-5): '))
if guess != secret_number:
print('Wrong! Try again.')
print('You got it!')
"""
Result
Guess the number (1-5): 2
Wrong! Try again.
Guess the number (1-5): 1
Wrong! Try again.
Guess the number (1-5): 3
You got it!
"""
- Declarações
breakecontinue: Usadas em loops para modificar a execução do loop. - A declaração
breaké usada para sair do loop imediatamente quando uma certa condição é atendida. Aqui está um exemplo de uso da declaraçãobreakpara uma lista dedeveloper_names:
developer_names = ['Jess', 'Naomi', 'Tom']
for developer in developer_names:
if developer == 'Naomi':
break
print(developer)
- A declaração
continueé usada para pular a iteração atual e passar para a próxima iteração do loop. Aqui está um exemplo de uso da declaraçãocontinueem vez de uma declaraçãobreak:
developer_names = ['Jess', 'Naomi', 'Tom']
for developer in developer_names:
if developer == 'Naomi':
continue
print(developer)
- Ambos os loops
forewhilepodem ser combinados com uma cláusulaelse, que é executada somente quando o loop não foi terminado por umbreak:
words = ['sky', 'apple', 'rhythm', 'fly', 'orange']
for word in words:
for letter in word:
if letter.lower() in 'aeiou':
print(f"'{word}' contains the vowel '{letter}'")
break
else:
print(f"'{word}' has no vowels")
Intervalos e seu uso em loops
- A função
range(): usada para gerar uma sequência de inteiros.
range(start, stop, step)
- O argumento
stopobrigatório é um inteiro (não inclusivo) que representa o ponto final da sequência de números gerada. Aqui está um exemplo de uso da funçãorange():
for num in range(3):
print(num)
- Se um argumento
startnão for especificado, o padrão será0. Por padrão, a sequência de inteiros incrementa de1. Você pode usar o argumento opcionalsteppara alterar o valor do incremento padrão. Aqui está um exemplo de geração de uma sequência de inteiros pares de 2 até, mas não incluindo, 11 (ou seja, inclui 10)
for num in range(2, 11, 2):
print(num)
- Se você não fornecer nenhum argumento para a função
range(), receberá umTypeError. - A função
range()aceita apenas inteiros como argumentos, não floats. Usar floats também resultará em umTypeError:
ERROR!
Traceback (most recent call last):
File "<main.py>", line 1, in <module>
TypeError: 'float' object cannot be interpreted as an integer
- Você pode usar um inteiro negativo para o argumento
steppara gerar uma sequência de inteiros em ordem decrescente:
for num in range(40, 0, -10):
print(num)
- A função
range()também pode ser usada para criar uma lista de inteiros ao usá-la com o construtorlist. O construtorlisté usado para converter um iterável em uma lista. Aqui está um exemplo de geração de uma lista de inteiros pares entre 2 e 10 inclusive:
numbers = list(range(2, 11, 2))
print(numbers) # [2, 4, 6, 8, 10]
funções enumerate() e zip() em Python
enumerate(): usada para iterar sobre uma sequência e acompanhar o índice de cada item nessa sequência. A funçãoenumerate()recebe um iterável como argumento e retorna um objetoenumerateque consiste no índice e valor de cada item no iterável.
languages = ['Spanish', 'English', 'Russian', 'Chinese']
for index, language in enumerate(languages):
print(f'Index {index} and language {language}')
# Result
# Index 0 and language Spanish
# Index 1 and language English
# Index 2 and language Russian
# Index 3 and language Chinese
- A função
enumerate()também pode ser usada fora de um loopfor:
languages = ['Spanish', 'English', 'Russian', 'Chinese']
print(list(enumerate(languages)))
# [(0, 'Spanish'), (1, 'English'), (2, 'Russian'), (3, 'Chinese')]
- A função
enumerate()também aceita um argumentostartopcional que especifica o valor inicial da contagem. Se esse argumento for omitido, a contagem começará em0. -
zip(): usada para iterar sobre múltiplos iteráveis em paralelo. Aqui está um exemplo usando a funçãozip()para iterar sobredeveloperseids:
developers = ['Naomi', 'Dario', 'Jessica', 'Tom']
ids = [1, 2, 3, 4]
for name, id in zip(developers, ids):
print(f'Name: {name}')
print(f'ID: {id}')
"""
Result
Name: Naomi
ID: 1
Name: Dario
ID: 2
Name: Jessica
ID: 3
Name: Tom
ID: 4
"""
Compreensões de lista em Python
- Definição: A compreensão de lista permite criar uma nova lista em uma única linha combinando o loop e a condição diretamente dentro dos colchetes. Isso torna o código mais curto e frequentemente mais fácil de ler.
even_numbers = [num for num in range(21) if num % 2 == 0]
print(even_numbers)
Funções iteráveis
filter(): Usada para filtrar elementos de um iterável com base em uma condição. Retorna um iterador que contém apenas os elementos que satisfazem a condição. Aqui está um exemplo de criação de uma nova lista apenas com palavras com mais de quatro caracteres:
words = ['tree', 'sky', 'mountain', 'river', 'cloud', 'sun']
def is_long_word(word):
return len(word) > 4
long_words = list(filter(is_long_word, words))
print(long_words) # ['mountain', 'river', 'cloud']
map(): Usada para aplicar uma função a cada item de um iterável e retornar um novo iterável com os resultados. Aqui está um exemplo de uso da funçãomap()para converter uma lista de temperaturas em celsius para fahrenheit:
celsius = [0, 10, 20, 30, 40]
def to_fahrenheit(temp):
return (temp * 9/5) + 32
fahrenheit = list(map(to_fahrenheit, celsius))
print(fahrenheit) # [32.0, 50.0, 68.0, 86.0, 104.0]
sum(): Usada para obter a soma de um iterável como uma lista ou tupla. Aqui está um exemplo de uso da funçãosum():
numbers = [5, 10, 15, 20]
total = sum(numbers)
print(total) # Result: 50
- Você também pode passar um argumento
startopcional que define o valor inicial para a soma. Aqui está um exemplo atualizado usando o argumentostartcomo argumento posicional:
numbers = [5, 10, 15, 20]
total = sum(numbers, 10) # positional argument
print(total) # 60
- Você também pode optar por usar o argumento
startcomo palavra-chave assim:
numbers = [5, 10, 15, 20]
total = sum(numbers, start=10) # keyword argument
print(total) # 60
Funções Lambda
- Definição: Uma função lambda em Python é uma forma concisa de criar uma função sem nome (uma função anônima).
- Funções lambda são frequentemente usadas como argumento para outra função. Aqui está um exemplo de uma função lambda:
numbers = [1, 2, 3, 4, 5]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers) # [2, 4]
- As melhores práticas para usar funções lambda incluem não atribuí-las a uma variável, mantê-las simples e legíveis, e usá-las para funções curtas e pontuais.
Dicionários
- Dicionários: Dicionários são estruturas de dados embutidas que armazenam coleções de pares chave-valor. As chaves precisam ser tipos de dados imutáveis. Esta é a sintaxe geral de um dicionário em Python:
dictionary = {
key1: value1,
key2: value2
}
- Construtor
dict(): O construtordict()é uma forma alternativa de construir o dicionário. Você passa uma lista de tuplas como argumento para o construtordict(). Essas tuplas contêm a chave como primeiro elemento e o valor como segundo elemento.
pizza = dict([('name', 'Margherita Pizza'), ('price', 8.9), ('calories_per_slice', 250), ('toppings', ['mozzarella', 'basil'])])
- Notação por colchetes: Para acessar o valor de um par chave-valor, você pode usar a sintaxe conhecida como notação por colchetes.
dictionary[key]
Métodos comuns de dicionário
- Método
get(): O métodoget()recupera o valor associado a uma chave. É semelhante à notação por colchetes, mas permite definir um valor padrão, evitando erros caso a chave não exista.
dictionary.get(key, default)
- Métodos
keys()evalues(): Os métodoskeys()evalues()retornam um objeto view com todas as chaves e valores do dicionário, respectivamente. Um objeto view é uma forma de ver o conteúdo de um dicionário sem criar uma cópia separada dos dados.
pizza = {
'name': 'Margherita Pizza',
'price': 8.9,
'calories_per_slice': 250
}
pizza.keys()
# dict_keys(['name', 'price', 'calories_per_slice'])
pizza.values()
# dict_values(['Margherita Pizza', 8.9, 250])
- Método
items(): O métodoitems()retorna um objeto view com todos os pares chave-valor do dicionário, incluindo tanto as chaves quanto os valores.
pizza.items()
# dict_items([('name', 'Margherita Pizza'), ('price', 8.9), ('calories_per_slice', 250)])
- Método
clear(): O métodoclear()remove todos os pares chave-valor do dicionário.
pizza.clear()
- Método
pop(): O métodopop()remove o par chave-valor com a chave especificada como primeiro argumento e retorna seu valor. Se a chave não existir, retorna o valor padrão especificado como segundo argumento. Se a chave não existir e o valor padrão não for especificado, umKeyErroré gerado.
pizza.pop('price', 10)
pizza.pop('total_price') # KeyError
- Método
popitem(): No Python 3.7 e superior, o métodopopitem()remove o último item inserido.
pizza.popitem()
- Método
update(): O métodoupdate()atualiza os pares chave-valor com os pares chave-valor de outro dicionário. Se tiverem chaves em comum, seus valores são sobrescritos. Novas chaves serão adicionadas ao dicionário como novos pares chave-valor.
pizza.update({ 'price': 15, 'total_time': 25 })
Looping sobre um dicionário
- Iterando sobre valores: Se você precisa iterar sobre os valores em um dicionário, pode escrever um loop
forcomvalues()para obter todos os valores de um dicionário.
products = {
'Laptop': 990,
'Smartphone': 600,
'Tablet': 250,
'Headphones': 70,
}
for price in products.values():
print(price)
Output:
990
600
250
70
- Iterando sobre chaves: Se você precisa iterar sobre as chaves no dicionário
productsacima, pode escreverproducts.keys()ouproductsdiretamente.
for product in products.keys():
print(product)
# Or
for product in products:
print(product)
Output:
Laptop
Smartphone
Tablet
Headphones
- Iterando sobre pares chave-valor: Se você precisa iterar sobre as chaves e seus valores correspondentes simultaneamente, pode iterar sobre
products.items(). Você obtém tuplas individuais com as chaves e seus valores correspondentes.
for product in products.items():
print(product)
Output:
('Laptop', 990)
('Smartphone', 600)
('Tablet', 250)
('Headphones', 70)
Para armazenar a chave e o valor em variáveis de loop separadas, você precisa separá-las com uma vírgula. A primeira variável armazena a chave e a segunda armazena o valor.
for product, price in products.items():
print(product, price)
Output:
Laptop 990
Smartphone 600
Tablet 250
Headphones 70
- Função
enumerate(): Se você precisa iterar sobre um dicionário enquanto mantém o controle de um contador, pode chamar a funçãoenumerate(). A função retorna um objetoenumerate, que atribui um inteiro a cada item, como um contador. Você pode iniciar o contador a partir de qualquer número, mas por padrão, ele começa em 0.
enumerate(). Por exemplo, com products.items(), você pode obter o par chave-valor inteiro além do índice:
for index, product in enumerate(products.items()):
print(index, product)
Output:
0 ('Laptop', 990)
1 ('Smartphone', 600)
2 ('Tablet', 250)
3 ('Headphones', 70)
Para personalizar o valor inicial da contagem, você pode passar um segundo argumento para enumerate(). Por exemplo, aqui estamos começando a contagem a partir de 1.
for index, product in enumerate(products.items(), 1):
print(index, product)
Output:
1 ('Laptop', 990)
2 ('Smartphone', 600)
3 ('Tablet', 250)
4 ('Headphones', 70)
Conjuntos
- Conjuntos: Conjuntos ou sets são estruturas de dados embutidas em Python que não permitem valores duplicados. Conjuntos são mutáveis e não ordenados, o que significa que seus elementos não são armazenados em uma ordem específica, então você não pode usar índices ou chaves para acessá-los. Além disso, conjuntos só podem conter valores de tipos de dados imutáveis, como números, strings e tuplas.
- Definindo um conjunto: Para definir um conjunto, você precisa escrever seus elementos entre chaves e separá-los com vírgulas.
my_set = {1, 2, 3, 4, 5}
- Definindo um conjunto vazio: Se você precisar definir um conjunto vazio, deve usar a função
set(). Apenas escrever chaves vazias criará automaticamente um dicionário.
set() # Set
{} # Dictionary
Métodos comuns de conjunto
- Método
add(): Você pode adicionar um elemento a um conjunto com o métodoadd(), passando o novo elemento como argumento.
my_set.add(6)
- Métodos
remove()ediscard(): Para remover um elemento de um conjunto, você pode usar o métodoremove()ou o métododiscard(), passando o elemento que deseja remover como argumento. O métodoremove()lançará umKeyErrorse o elemento não for encontrado, enquanto o métododiscard()não lançará.
my_set.remove(4)
my_set.discard(4)
- Método
clear(): O métodoclear()remove todos os elementos do conjunto.
my_set.clear()
Operações matemáticas com conjuntos
- Métodos
issubset()eissuperset(): Os métodosissubset()eissuperset()verificam se um conjunto é subconjunto ou superconjunto de outro conjunto, respectivamente.
my_set = {1, 2, 3, 4, 5}
your_set = {2, 3, 4, 5}
print(your_set.issubset(my_set)) # True
print(my_set.issuperset(your_set)) # True
- Método
isdisjoint(): O métodoisdisjoint()verifica se dois conjuntos são disjuntos, ou seja, se não têm elementos em comum.
my_set = {1, 2, 3}
your_set = {4, 5, 6}
print(my_set.isdisjoint(your_set)) # True
- Operador união (
|): O operador união|retorna um novo conjunto com todos os elementos de ambos os conjuntos.
my_set = {1, 2, 3}
your_set = {4, 5, 6}
my_set | your_set # {1, 2, 3, 4, 5, 6}
- Operador interseção (
&): O operador interseção&retorna um novo conjunto apenas com os elementos que os conjuntos têm em comum.
my_set = {1, 2, 3, 4, 5}
your_set = {2, 3, 4, 6}
my_set & your_set # {2, 3, 4}
- Operador diferença (
-): O operador diferença-retorna um novo conjunto com os elementos do primeiro conjunto que não estão no outro conjunto.
my_set = {1, 2, 3, 4, 5}
your_set = {2, 3, 4, 6}
my_set - your_set # {1, 5}
- Operador diferença simétrica (
^): O operador diferença simétrica^retorna um novo conjunto com os elementos que estão no primeiro ou no segundo conjunto, mas não em ambos.
my_set = {1, 2, 3, 4, 5}
your_set = {2, 3, 4, 6}
my_set ^ your_set # {1, 5, 6}
- Operador
in: Você pode verificar se um elemento está em um conjunto ou não com o operadorin.
print(5 in my_set)
Biblioteca padrão do Python
- Biblioteca padrão do Python: Uma biblioteca oferece código pré-escrito e reutilizável, como funções, classes e estruturas de dados, que você pode reutilizar em seus projetos. O Python possui uma biblioteca padrão extensa com módulos embutidos que implementam soluções padronizadas para muitos problemas e tarefas. Alguns exemplos de módulos embutidos populares são
math,random,re(abreviação de "expressões regulares") edatetime.
Declaração Import
- Declaração de importação: Para acessar os elementos definidos em módulos embutidos, você usa uma declaração de importação. Declarações de importação geralmente são escritas no topo do arquivo. Elas funcionam da mesma forma para funções, classes, constantes, variáveis e quaisquer outros elementos definidos no módulo.
- Declaração básica de importação: Você pode usar a palavra-chave
importseguida do nome do módulo:
import module_name
Então, se precisar chamar uma função desse módulo, você usaria a notação de ponto, com o nome do módulo seguido do nome da função.
module_name.function_name()
Por exemplo, você escreveria o seguinte no seu código para importar o módulo math e obter a raiz quadrada de 36:
import math
math.sqrt(36)
- Importando um módulo com um nome diferente: Se precisar importar o módulo com um nome diferente (também conhecido como "alias"), você pode usar
asseguido do alias no final da declaração de importação. Isso é frequentemente usado para nomes de módulos longos ou para evitar conflitos de nomes.
import module_name as module_alias
Por exemplo, para se referir ao módulo math como m no seu código, você pode atribuir um alias assim:
import math as m
Então, você pode acessar os elementos do módulo usando o alias:
m.sqrt(36)
- Importando elementos específicos: Se você não precisa de tudo de um módulo, pode importar elementos específicos usando
from. Nesse caso, a declaração de importação começa comfrom, seguida do nome do módulo, depois a palavra-chaveimporte, finalmente, os nomes dos elementos que deseja importar.
from module_name import name1, name2
Então, você pode usar esses nomes sem o prefixo do módulo no seu script Python. Por exemplo:
from math import radians, sin, cos
angle_degrees = 40
angle_radians = radians(angle_degrees)
sine_value = sin(angle_radians)
cos_value = cos(angle_radians)
print(sine_value) # 0.6427876096865393
print(cos_value) # 0.766044443118978
Isso é útil, mas pode resultar em conflitos de nomes se você já tiver funções ou variáveis com o mesmo nome. Tenha isso em mente ao escolher qual tipo de declaração de importação usar.
Se precisar atribuir aliases a esses nomes, também pode fazer isso, usando a palavra-chave as seguida do alias.
from module_name import name1 as alias1, name2 as alias2
- Declaração de importação com asterisco (
*): O asterisco indica ao Python que você quer importar tudo daquele módulo, mas quer importar de forma que não precise usar o nome do módulo como prefixo.
from module_name import *
Por exemplo, se usar isso para importar o módulo math, poderá chamar qualquer função definida nesse módulo sem especificar o nome do módulo como prefixo.
from math import *
print(sqrt(36)) # 6.0
No entanto, isso geralmente é desencorajado porque pode causar colisões de namespace e dificultar saber de onde os nomes vêm.
if __name__ == '__main__'
- Variável
__name__:__name__é uma variável embutida especial em Python. Quando um arquivo Python é executado diretamente, o Python define o valor dessa variável como a string"__main__". Mas se o arquivo Python for importado como um módulo em outro script Python, o valor da variável__name__é definido como o nome desse módulo.
if __name__ == '__main__':
# Code
Erros comuns em Python
- SyntaxError: o erro que o Python gera quando seu código não segue suas regras de sintaxe. Por exemplo, o código
print("Hello there"causará um erro de sintaxe com a mensagemSyntaxError: '(' was never closed, porque o código está sem um parêntese de fechamento. - NameError: o Python gera um
NameErrorquando você tenta acessar uma variável ou função que não definiu. Por exemplo, se você tiver a linhaprint(username)no seu código sem ter definido antes uma variávelusername, receberá um erro de nome com a mensagemNameError: name 'username' is not defined. - TypeError: esse é o erro que o Python lança quando você realiza uma operação entre dois ou mais tipos de dados incompatíveis. Por exemplo, se tentar somar uma string com um número, receberá o erro
TypeError: can only concatenate str (not "int") to str. - IndexError: você receberá um
IndexErrorse acessar um índice que não existe em uma lista ou outras sequências como tupla e string. Por exemplo, em uma stringHello world, o índice do último caractere é10. Se você acessar um caractere assim,greet = "hello world"; print(greet[11]), receberá um erro com a mensagemIndexError: string index out of range. - AttributeError: o Python gera esse erro quando você tenta usar um método ou propriedade que não existe em um objeto daquele tipo. Por exemplo, chamar
.append()em uma string como"hello".append("!")causará um erro com a mensagemAttributeError: 'str' object has no attribute 'append'.
Boas técnicas de depuração em Python
- Usar a função
print: Inserir declaraçõesprint()em vários pontos do seu código durante a depuração ajuda a ver os valores das variáveis e como o fluxo do código acontece. - Usar o depurador embutido do Python (
pdb): O Python oferece um módulopdbpara depuração. Ele faz parte da biblioteca padrão do Python, então está sempre disponível para usar. Compdb, você pode definir um rastreamento com a funçãoset_trace()para começar a executar o código passo a passo e inspecionar variáveis de forma interativa. - Aproveitar as ferramentas de depuração das IDEs: Muitos ambientes de desenvolvimento integrados (IDEs) e editores de código como Pycharm e VS Code oferecem ferramentas de depuração com pontos de interrupção, execução passo a passo, inspeção de variáveis e outros recursos de depuração.
Tratamento de exceções
try...except: Isso é usado para executar um bloco de código que pode gerar uma exceção. O blocotryé onde você espera que um erro possa ocorrer, enquanto o blocoexceptcaptura uma exceção específica e é executado se esse erro ocorrer. Veja um exemplo:
try:
print(22 / 0)
except ZeroDivisionError:
print('You can\'t divide by zero!')
# You can't divide by zero!
Você também pode encadear vários blocos except para tratar mais tipos de exceções:
try:
number = int(input('Enter a number: '))
print(22 / number)
except ZeroDivisionError:
print('You cannot divide by zero!')
# You cannot divide by zero! prints when you enter 0
except ValueError:
print('Please enter a valid number!')
# Please enter a valid number! prints when you don't enter an integer
elseefinally: Esses blocos estendem otry...except. Se nenhuma exceção ocorrer, o blocoelseé executado. O blocofinallysempre é executado, independentemente de erros.
try:
result = 100 / 4
except ZeroDivisionError:
print('You cannot divide by zero!') # This will not run
else:
print(f'Result is {result}') # Result is 25.0
finally:
print('Execution complete!') # Execution complete!
- Objeto de exceção: Isso permite acessar a própria exceção para facilitar a depuração e imprimir a mensagem de erro direta. Para acessar o objeto de exceção, você precisa usar a palavra-chave
as. Veja um exemplo:
try:
value = int('This will raise an error')
except ValueError as e:
print(f'Caught an error: {e}')
# Caught an error: invalid literal for int() with base 10: 'This will raise an error'
- A declaração
raise: Isso permite que você levante manualmente uma exceção. Você pode usá-la para lançar uma exceção quando uma certa condição for atendida. Veja um exemplo:
def divide(a, b):
if b == 0:
raise ZeroDivisionError('You cannot divide by zero')
return a / b
Sinalização de exceções
A declaraçãoraise também é útil quando você cria suas próprias exceções personalizadas, pois pode usá-la para lançar uma exceção com uma mensagem personalizada. Aqui está um exemplo disso:
class InvalidCredentialsError(Exception):
def __init__(self, message="Invalid username or password"):
self.message = message
super().__init__(self.message)
def login(username, password):
stored_username = "admin"
stored_password = "password123"
if username != stored_username or password != stored_password:
raise InvalidCredentialsError()
return f"Welcome, {username}!"
Veja como você pode usar a função login com a exceção InvalidCredentialsError:
# failed login attempt
try:
message = login("user", "wrongpassword")
except InvalidCredentialsError as e:
print(f"Login failed: {e}")
else:
print(message)
# successful login attempt
try:
message = login("admin", "password123")
except InvalidCredentialsError as e:
# This block is not executed because the login was successful
print(f"Login failed: {e}")
else:
# The else block runs if the 'try' block completes without an exception
print(message)
A declaração raise também pode ser usada com a palavra-chave from para encadear exceções, mostrando a relação entre diferentes erros:
def parse_config(filename):
try:
with open(filename, 'r') as file:
data = file.read()
return int(data)
except FileNotFoundError:
raise ValueError('Configuration file is missing') from None
except ValueError as e:
raise ValueError('Invalid configuration format') from e
config = parse_config('config.txt')
Classes e objetos em Python
- Definição de classe: Uma classe é um modelo para criar objetos. Ela define o comportamento que um objeto terá por meio de seus atributos e métodos. Aqui está um exemplo básico de definição de classe em Python:
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print(f'{self.name.upper()} says woof woof!')
- Criando objetos: Objetos são instâncias de uma classe. Eles são criados ao chamar a classe com os argumentos necessários.
dog1 = Dog('Jack', 3)
dog2 = Dog('Thatcher', 5)
dog1.bark() # JACK says woof woof!
dog2.bark() # THATCHER says woof woof!
- Chamando métodos em objetos: Você pode chamar métodos em objetos para executar ações ou obter informações.
object_name1.method_name()
object_name2.method_name()
- Diferença entre classe e objeto: Uma classe é um modelo reutilizável, enquanto um objeto é uma instância específica dessa classe com dados reais.
Atributos
- Atributos de instância: definidos em
__init__()usandoself, e únicos para cada objeto. - Atributos de classe: definidos diretamente dentro da classe e compartilhados por todas as instâncias.
class Dog:
species = 'French Bulldog' # Class attribute
def __init__(self, name):
self.name = name # Instance attribute
print(Dog.species) # French Bulldog
jack = Dog('Jack')
print(jack.name) # Jack
print(jack.species) # French Bulldog
Métodos
- Métodos: Funções definidas dentro de uma classe que operam nos atributos do objeto.
class Car:
def __init__(self, color, model):
self.color = color
self.model = model
def describe(self):
return f'This car is a {self.color} {self.model}'
my_car_1 = Car('red', 'Tesla Model S')
print(my_car_1.describe()) # This car is a red Tesla Model S
- Acessando métodos: Faça chamadas de métodos em objetos usando a notação de ponto. Aqui está um exemplo de chamada do método
describeem dois objetos carro diferentes:
class Car:
def __init__(self, color, model):
self.color = color
self.model = model
def describe(self):
return f'This car is a {self.color} {self.model}'
my_car_1 = Car('red', 'Tesla Model S')
my_car_2 = Car('green', 'Lamborghini Revuelto')
print(my_car_1.describe()) # Calling method using the dot notation
print(my_car_2.describe()) # Calling method using the dot notation
Métodos dunder (mágicos)
- Definição: Métodos especiais que começam e terminam com dois underscores (por exemplo,
__init__,__len__,__str__,__eq__). O Python os usa internamente para operações embutidas.
class Book:
def __init__(self, title, pages):
self.title = title
self.pages = pages
def __len__(self):
return self.pages
def __str__(self):
return f"'{self.title}' has {self.pages} pages"
def __eq__(self, other):
return self.pages == other.pages
book1 = Book('Built Wealth Like a Boss', 420)
print(len(book1)) # 420
print(str(book1)) # 'Built Wealth Like a Boss' has 420 pages
- Chamando métodos dunder indiretamente: Você não precisa chamar métodos dunder diretamente. Em vez disso, o Python os chama automaticamente quando certas ações acontecem. Essas operações incluem:
- operações aritméticas como adição, subtração, multiplicação, divisão e outras.
__add__()é chamado para adição,__sub__()para subtração,__mul__()para multiplicação e__truediv__()para divisão. - operações com strings como concatenação, repetição, formatação e conversão para texto.
__add__()é chamado para concatenação,__mul__()para repetição,__format__()para formatação,__str__()e__repr__()para conversão em texto, e assim por diante. - operações de comparação como igualdade, menor que, maior que e outras.
__eq__()é chamado para checagens de igualdade,__lt__()para menor que,__gt__()para maior que, e assim por diante. - operações de iteração como tornar um objeto iterável e avançar pelos itens.
__iter__()é chamado para retornar um iterador e__next__()para buscar o próximo item.
Exemplo do mundo real: carrinho de compras
- Classe Cart com métodos dunder: permite adicionar, remover, iterar e verificar conteúdos com comportamento embutido.
class Cart:
def __init__(self):
self.items = []
def add(self, item):
self.items.append(item)
def remove(self, item):
if item in self.items:
self.items.remove(item)
else:
print(f'{item} is not in cart')
def list_items(self):
return self.items
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
def __contains__(self, item):
return item in self.items
def __iter__(self):
return iter(self.items)
cart = Cart()
cart.add('Laptop')
print(len(cart)) # 1
print('Laptop' in cart) # True
O que é programação orientada a objetos?
- Programação orientada a objetos: Um estilo de programação em que os desenvolvedores tratam tudo no código como um objeto do mundo real. É popularmente chamada de OOP. Os quatro princípios-chave que ajudam a organizar e gerenciar o código de forma eficaz são encapsulamento, herança, polimorfismo e abstração
- Classes: O modelo para criar objetos. Cada objeto criado a partir de uma classe tem atributos que definem dados e métodos que determinam os comportamentos do objeto.
O que é encapsulamento?
- Encapsulamento: O agrupamento dos atributos e métodos de um objeto em uma única unidade. Ele permite esconder o estado interno do objeto atrás de um conjunto simples de métodos e atributos públicos que funcionam como portas. Por trás dessas portas estão atributos e métodos privados que controlam como os dados mudam e quem pode vê-los.
- Exemplo de encapsulamento: Se você quer controlar o saldo de uma carteira, permitirá depósitos e retiradas, mas não vai querer que ninguém mexa diretamente no saldo da carteira:
class Wallet:
def __init__(self, balance):
self.__balance = balance # Private attribute
def deposit(self, amount):
if amount > 0:
self.__balance += amount # Add to the balance safely
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount # Remove from the balance safely
account = Wallet(500)
print(account.__balance) # AttributeError: 'Wallet' object has no attribute '__balance'
- Diferença entre prefixar atributos com um ou dois underscores: Prefixar atributos e métodos com um underscore significa que eles são destinados para uso interno. Isso é uma convenção e não impede o acesso aos atributos de fora. Prefixar atributos e métodos com dois underscores impede efetivamente que sejam acessados fora da sua classe.
O que são getters e setters?
- Getters e setters: Métodos que permitem controlar como os atributos de uma classe são acessados e modificados. Você recupera valores com getters e atribui valores com setters.
- Propriedades: Elas conectam getters e setters e permitem o acesso aos dados. Executam lógica extra nos bastidores quando você obtém, atribui ou exclui valores.
- Por que propriedades em vez de métodos: Propriedades são usadas em vez de métodos para melhor legibilidade e código mais limpo. Elas permitem acessar valores com notação de ponto, como atributos normais, sem parênteses.
- Criando um getter: Para criar um getter, você usa o decorador
@property. Aqui está um getter que obtém o raio de um círculo:
class Circle:
def __init__(self, radius):
self.radius = radius # Calling the setter
@property
def radius(self): # A getter to get the radius
return self._radius
@property
def area(self): # A getter to calculate area
return 3.14 * (self._radius ** 2)
my_circle = Circle(3)
print(my_circle.radius) # 3
print(my_circle.area) # 28.26
Usar self.radius dentro do __init__() garante que o setter seja executado durante a criação do objeto, assim valores inválidos para o raio são detectados imediatamente.
- Criando um setter: Para criar o setter que vai atribuir o raio, você precisa definir outro método com o mesmo nome e usar
@<property_name>.setteracima dele:
class Circle:
def __init__(self, radius):
self.radius = radius # Calling the setter
@property
def radius(self): # A getter to get the radius
return self._radius
@radius.setter
def radius(self, value): # A setter to set the radius
if value <= 0:
raise ValueError('Radius must be positive')
self._radius = value
my_circle = Circle(3)
print('Initial radius:', my_circle.radius) # Initial radius: 3
my_circle.radius = 8
print('After modifying the radius:', my_circle.radius) # After modifying the radius: 8
- Como o Python lida com getters e setters: Depois de definir getters e setters, o Python os chama automaticamente nos bastidores sempre que você usa a sintaxe normal de atributo assim:
my_circle.radius # This will call the getter
my_circle.radius = 4 # This will call the setter
Dentro do setter, você não deve atribuir ao nome da propriedade em si porque isso causará um RecursionError.
- Deleter: Depois de atribuir e obter um valor com setter e getter, você pode controlar como ele é excluído com um
deleter. Um deleter executa lógica personalizada quando você usa a declaraçãodelem uma propriedade. Para criar um deleter, você usa o decorador@<property_name>.deleter.
# Deleter
@radius.deleter
def radius(self):
print("Deleting radius...")
del self._radius
O que é herança e como ela promove a reutilização de código?
- Herança: o processo pelo qual uma classe filho usa os atributos e métodos de uma classe pai. A herança promove a reutilização de código, fornece hierarquias claras e personaliza comportamentos sem precisar reescrever tudo. Para implementar herança, uma classe filho recebe o nome de uma classe pai:
class Parent:
# Parent attributes and methods
class Child(Parent):
# Child inherits, extends, and/or overrides where necessary
- Herança simples e múltipla: quando uma classe filho herda propriedades e métodos de um único pai, como você viu acima, esse processo é chamado de herança simples. Quando uma classe filho herda propriedades e métodos de mais de um pai, isso é herança múltipla. Veja a sintaxe para isso:
class Parent:
# Attributes and methods for Parent
class Child:
# Attributes and methods for Child
class GrandChild(Parent, Child):
# GrandChild inherits from both Parent and Child
# GrandChild can combine or override behavior from each
- Função
super(): uma função que permite você fazer a chamada de um método de uma classe pai, quando uma classe tem uma implementação diferente desse método, ou estende o método, sem duplicar código.
O que é polimorfismo e como ele promove a reutilização de código?
- Polimorfismo: O princípio da POO que permite que diferentes classes usem o mesmo nome de método, mas cada classe o implemente de forma diferente quando chamado. Aqui está a sintaxe para isso:
class A:
def action(self): ...
class B:
def action(self): ...
class C:
def action(self): ...
Class().method() # Works for A, B, or C
- Polimorfismo baseado em herança: Um pai define um método, e cada classe filho o adapta para seu uso.
O que é name mangling e como ele funciona?
- Name mangling: um processo em que o Python renomeia internamente um atributo prefixado com dois underscores adicionando um underscore e o nome da classe como prefixo, transformando
__attributeem_ClassName__attribute. - O propósito do name mangling: o principal objetivo do name mangling é evitar a sobrescrição acidental de atributos e métodos quando você usa herança. Aqui está um código que torna isso mais fácil de entender:
class Parent:
def __init__(self):
self.__data = 'Parent data'
class Child(Parent):
def __init__(self):
super().__init__()
self.__data = 'Child data'
c = Child()
print(c.__dict__) # {'_Parent__data': 'Parent data', '_Child__data': 'Child data'}
O que é abstração e como ela ajuda a manter sistemas complexos organizados?
- Abstração: Um conceito de programação em que detalhes complexos de implementação de um objeto ou sistema são ocultados e apenas os recursos essenciais são mostrados. Em Python e outras linguagens de programação, a abstração simplifica sistemas complexos aumentando a reutilização.
- Exemplo de abstração: Um bom exemplo de abstração no dia a dia é um carro que permite usar apenas o volante, os pedais e a alavanca de câmbio sem precisar saber como o motor ou os freios funcionam.
- Como o Python implementa abstração: O Python implementa abstração por meio do módulo
abc. O módulo fornece a classeABC(classe base abstrata) e o decorador@abstractmethod. Uma classe base abstrata (ABC) define os métodos e propriedades comuns que as subclasses devem implementar. Ela não pode ser instanciada. - Como o método abstrato é definido: Um método abstrato é definido com
@abstractmethode deve ser sobrescrito nas subclasses, mesmo que tenha uma implementação padrão. A sintaxe básica da abstração é assim:
from abc import ABC, abstractmethod
# Define an abstract base class
class AbstractClass(ABC):
@abstractmethod
def abstract_method(self):
pass
# Concrete subclass that implements the abstract method
class ConcreteClassOne(AbstractClass):
def abstract_method(self):
print('Implementation in ConcreteClassOne')
# Another concrete subclass
class ConcreteClassTwo(AbstractClass):
def abstract_method(self):
print('Implementation in ConcreteClassTwo')
Algoritmos e notação big O
- Algoritmos: um conjunto de instruções claras e sem ambiguidades para resolver um problema ou realizar uma tarefa. Algoritmos devem terminar em um número finito de passos e cada passo deve ser preciso e sem ambiguidades.
- Notação big O: descreve o desempenho no pior caso, ou taxa de crescimento, de um algoritmo conforme o tamanho da entrada aumenta. Ela foca em como o uso de recursos cresce com o tamanho da entrada, ignorando fatores constantes e termos de ordem inferior.
Complexidades de tempo comuns
- O(1) - tempo constante: o algoritmo leva o mesmo tempo independentemente do tamanho da entrada.
def check_even_or_odd(number):
if number % 2 == 0:
return 'Even'
else:
return 'Odd'
- O(log n) - tempo logarítmico: o tempo aumenta lentamente conforme a entrada cresce. Comum em algoritmos que reduzem repetidamente o tamanho do problema por uma fração (como a busca binária).
- O(n) - tempo linear: o tempo de execução aumenta proporcionalmente ao tamanho da entrada.
for grade in grades:
print(grade)
- O(n log n) - tempo log-linear: complexidade de tempo comum em algoritmos eficientes de ordenação como merge sort e quick sort.
- O(n²) - tempo quadrático: o tempo de execução aumenta quadraticamente. Frequentemente visto em loops aninhados.
for i in range(n):
for j in range(n):
print("Hello, World!")
Complexidade de espaço
- O(1) - espaço constante: o algoritmo usa a mesma quantidade de memória independentemente do tamanho da entrada.
- O(n) - espaço linear: o uso de memória cresce proporcionalmente ao tamanho da entrada.
- O(n²) - espaço quadrático: o uso de memória cresce quadraticamente com o tamanho da entrada.
Técnicas de resolução de problemas
- Entendendo o problema: Leia a declaração do problema várias vezes. Identifique a entrada, a saída esperada e como transformar a entrada na saída.
- Pseudocódigo: Descrição em alto nível da lógica do algoritmo que é independente da linguagem. Usa linguagem escrita comum misturada com construções de programação como
IF,ELSE,FOR,WHILE.
GET original_string
SET reversed_string = ""
FOR EACH character IN original_string:
ADD character TO THE BEGINNING OF reversed_string
DISPLAY reversed_string
- Casos extremos: Entradas específicas e válidas que ocorrem nos limites do que um algoritmo deve tratar. Sempre considere e teste casos extremos.
Arrays
- Arrays estáticos: têm tamanho fixo determinado na inicialização. Elementos armazenados em locais de memória adjacentes. O tamanho não pode ser alterado durante a execução do programa.
- Arrays dinâmicos: podem crescer ou diminuir automaticamente durante a execução do programa. Lidam com redimensionamento por meio de cópia automática para arrays maiores quando necessário.
Listas em Python (arrays dinâmicos)
numbers = [3, 4, 5, 6]
# Access elements
numbers[0] # 3
# Update elements
numbers[2] = 16
# Add elements
numbers.append(7)
numbers.insert(3, 15) # Insert at specific index
# Remove elements
numbers.pop(2) # Remove at specific index
numbers.pop() # Remove last element
Complexidades de tempo para arrays dinâmicos
- Acesso: O(1)
- Inserção no final: O(1) média, O(n) quando é necessário redimensionar
- Inserção no meio: O(n)
- Exclusão: O(n) para o meio, O(1) para o final
Pilhas
- Pilhas: estrutura de dados Last-In, First-Out (LIFO). Elementos são adicionados e removidos apenas do topo.
- Operação push: adicionar um elemento ao topo da pilha. Complexidade de tempo: O(1).
- Operação pop: remover um elemento do topo da pilha. Complexidade de tempo: O(1).
# Using Python list as stack
stack = []
# Push operations
stack.append(1)
stack.append(2)
stack.append(3)
# Pop operations
top_element = stack.pop() # Returns 3
Filas
- Filas: estrutura de dados First-In, First-Out (FIFO). Elementos são adicionados na parte de trás e removidos da frente.
- Operação de enfileirar: adicionar um elemento na parte de trás da fila. Complexidade de tempo: O(1).
- Operação de desenfileirar: remover um elemento da frente da fila. Complexidade de tempo: O(1).
from collections import deque
# Using deque for efficient queue operations
queue = deque()
# Enqueue operations
queue.append(1)
queue.append(2)
queue.append(3)
# Dequeue operations
first_element = queue.popleft() # Returns 1
Listas ligadas
- Listas ligadas: Estrutura de dados linear onde cada nó contém dados e uma referência para o próximo nó. Os nós estão conectados como uma corrente.
Listas ligadas simples
- Estrutura: Cada nó tem dados e uma referência para o próximo nó.
- Percurso: Só é possível avançar do início ao fim.
- Nó cabeça: Primeiro nó da lista, geralmente o único nó acessível diretamente.
- Nó cauda: Último nó da lista, aponta para
None.
Operações e complexidades de tempo
- Inserir no início: O(1)
- Inserir no fim: O(n) - é preciso percorrer até o fim
- Inserir no meio: O(n) - é preciso percorrer até a posição
- Excluir do início: O(1)
- Excluir do fim: O(n) - é preciso percorrer para encontrar o nó anterior
- Excluir do meio: O(n) - é preciso percorrer para encontrar o nó
Listas duplamente ligadas
- Estrutura: Cada nó tem dados e duas referências: para o próximo nó e para o nó anterior.
- Percurso: Pode avançar em ambas as direções.
- Memória: Requer mais memória que listas ligadas simples devido à referência extra.
Mapas hash e conjuntos
Maps e mapas hash
- Map (tipo abstrato de dado): Gerencia coleções de pares chave-valor. Cada chave deve ser única, mas os valores podem se repetir.
- Mapa hash: Implementação concreta do map ADT usando técnica de hashing. Usa função hash para gerar valores hash para as chaves, que determinam o local de armazenamento no array subjacente.
Dicionários Python (mapas hash)
# Creating dictionaries
my_dictionary = {
"A": 1,
"B": 2,
"C": 3
}
# Alternative creation
my_dictionary = dict(A=1, B=2, C=3)
# Access and modify
value = my_dictionary["A"] # 1
my_dictionary["A"] = 4 # Update value
del my_dictionary["A"] # Remove key-value pair
# Check membership
"C" in my_dictionary
# Get keys, values, items
my_dictionary.keys()
my_dictionary.values()
my_dictionary.items()
Complexidades de tempo para mapas hash
- Caso médio: O(1) para inserir, obter, excluir
- Pior caso: O(n) quando ocorrem muitas colisões de hash
Sets
- Conjuntos: Coleções não ordenadas de elementos únicos. Não permitem duplicatas, nem mantêm ordem específica.
- Apenas elementos imutáveis: Conjuntos só podem conter tipos de dados imutáveis (números, strings, tuplas) porque os valores hash devem permanecer constantes.
# Creating sets
numbers = {1, 2, 3, 4}
empty_set = set() # Must use set(), not {}
# Add and remove elements
numbers.add(5)
numbers.remove(4) # Raises KeyError if not found
numbers.discard(4) # No error if not found
# Set operations
set_a = {1, 2, 3, 4}
set_b = {2, 3, 4, 5, 6}
# Union, intersection, difference, symmetric difference
set_a.union(set_b) # or set_a | set_b
set_a.intersection(set_b) # or set_a & set_b
set_a.difference(set_b) # or set_a - set_b
set_a.symmetric_difference(set_b) # or set_a ^ set_b
# Subset and superset checks
set_a.issubset(set_b)
set_a.issuperset(set_b)
set_a.isdisjoint(set_b)
# Membership testing
5 in numbers
Complexidades de tempo para conjuntos
- Caso médio: O(1) para adicionar, remover, testar associação
- Pior caso: O(n) devido a colisões de hash
Hash Collisions
- Colisão de hash: ocorre quando duas chaves diferentes produzem o mesmo valor de hash.
- Estratégias de resolução de colisão:
- Encadeamento: cada índice do array aponta para uma lista ligada que armazena todos os elementos com o mesmo valor de hash
- Endereçamento aberto: busca pelo próximo índice disponível usando uma sequência predefinida
Quando usar cada estrutura de dados
- Listas: quando você precisa de acesso ordenado e indexado e não sabe o tamanho antecipadamente
- Pilhas: para operações LIFO (funcionalidade de desfazer, avaliação de expressões, retrocesso)
- Filas: para operações FIFO (agendamento de tarefas, busca em largura)
- Listas ligadas: quando há inserção/remoção frequente no início, tamanho desconhecido, sem necessidade de acesso aleatório
- Hash maps: para buscas rápidas por chave-valor, contagem de ocorrências, cache
- Conjuntos: para verificação de unicidade, operações matemáticas com conjuntos, remoção de duplicatas
Algoritmos de busca
Algoritmos de busca permitem que você procure um alvo dentro de uma determinada lista de itens. Em ciência da computação, existem dois algoritmos de busca que você deve conhecer. Eles são algoritmos de busca linear e busca binária. É importante entender as diferenças entre os dois algoritmos e quando usar cada um.Busca linear
- A busca linear itera por uma lista de itens, verificando cada item desde o início até que o item alvo seja encontrado.
- Se o item alvo for encontrado, o índice onde ele está localizado na lista é retornado.
- Se o alvo não for encontrado, ele retorna
-1, o que significa índice inválido na maioria das linguagens de programação. - Porque a busca linear verifica cada item até encontrar o alvo, ela não é eficiente para uma lista grande de itens.
- A complexidade de tempo da busca linear é
O(n)porque o tempo que leva para percorrer a lista cresce linearmente com o tamanho da lista. - A complexidade de espaço da busca linear é
O(1)porque não requer espaço adicional para percorrer a lista.
Busca binária
- A busca binária funciona dividindo uma lista de itens ao meio e verificando se o valor alvo está no meio da lista.
- A condição para a busca binária funcionar é que os itens na lista devem estar em ordem crescente.
- A busca binária é um algoritmo mais eficiente para buscar em uma lista grande de itens porque divide a lista ao meio e ignora qualquer metade onde o alvo não está.
- Se o item alvo for encontrado no meio da lista, o índice do item alvo é retornado.
- Se o item não for encontrado, o algoritmo verifica se o item alvo está na metade esquerda ou direita da lista.
- Ele continua dividindo as partes restantes da lista em metades até o item alvo ser encontrado.
- Se o item alvo finalmente não for encontrado na lista, retorna
-1 - A complexidade de tempo da busca binária é
O(log n)porque o tempo que leva para buscar na lista cresce logaritmicamente com o tamanho da lista. - A complexidade de espaço da busca binária é
O(1)porque não requer espaço adicional para buscar na lista.
Como a Busca Linear Difere da Busca Binária
- A busca binária é mais adequada para uma lista grande de itens em comparação com a busca linear.
- A complexidade de tempo da busca linear é
O(n)porque o tempo que leva para percorrer a lista cresce linearmente com o tamanho da lista. - A complexidade de tempo da busca binária é
O(log n)porque o tempo que leva para buscar na lista cresce logaritmicamente com o tamanho da lista.
Algoritmos de Ordenação e Dividir-e-Conquistar
Em ciência da computação, divide-and-conquer é uma técnica usada para dividir um problema em subproblemas menores para que sejam mais fáceis de resolver. Recursão é a técnica frequentemente empregada em divide-and-conquer e divide-and-conquer é uma estratégia poderosa usada para implementar muitos algoritmos de ordenação eficientes como merge sort.Merge Sort
- Merge sort é um algoritmo de ordenação que segue a abordagem de dividir e conquistar.
- Funciona dividindo recursivamente uma lista em sublistas menores até que cada sublista contenha apenas um elemento.
- Em seguida, ele mescla repetidamente as sublistas de volta em uma ordem ordenada.
- A complexidade de tempo do merge sort é
O(n log n)porque a lista é continuamente dividida ao meio(log n)e depois mesclada(O(n)). - A complexidade de espaço do merge sort é
O(n)porque ele não é um algoritmo de ordenação in-place.
Visão geral de grafos
Um grafo é um conjunto de nós (vértices) conectados por arestas (conexões). Cada nó pode se conectar a vários outros nós, formando uma rede. Os diferentes tipos de grafos incluem:- Direcionado: as arestas têm uma direção (de um nó para outro), geralmente representadas por linhas retas e setas.
- Não direcionado: as arestas não têm direção, representadas por linhas simples.
- Com vértice: cada nó está associado a um rótulo ou identificador.
- Cíclico: contém ciclos (um caminho que começa e termina no mesmo nó).
- Acíclico (DAG): não contém ciclos.
- Com rótulo na aresta: cada aresta tem um rótulo geralmente desenhado ao lado da aresta correspondente.
- Ponderado: as arestas têm pesos (valores) associados, que podem ser usados para realizar operações aritméticas.
- Desconectado: contém dois ou mais nós que não estão conectados por nenhuma aresta.
Travessia de grafos
Isso envolve visitar todos os nós em um grafo. Os dois principais algoritmos são:- Busca em largura (BFS)
- Usa uma fila.
- Explora nível por nível.
- Encontra o caminho mais curto em grafos não ponderados.
- Busca em profundidade (DFS)
- Usa uma pilha (ou recursão).
- Explora completamente um ramo antes de retroceder.
- Útil para detectar ciclos e buscar caminhos.
Representações de grafos
Grafos podem ser representados de duas formas principais:- Lista de adjacência
- Cada nó tem uma lista de seus vizinhos.
- Espaço eficiente para grafos esparsos.
- Fácil iterar sobre os vizinhos.
- Matriz de adjacência
- Um array 2D onde linhas e colunas representam nós.
- Espaço intensivo para grafos grandes.
- Rápido para verificar se existe uma aresta entre dois nós.
Árvores
Uma árvore é um tipo especial de grafo que é acíclico e conectado. As propriedades principais incluem:- Não possuem loops ou ciclos (caminhos onde os nós inicial e final são os mesmos).
- Devem ser conectadas (todo nó pode ser alcançado a partir de qualquer outro nó).
Tipos comuns de árvores
Os tipos mais comuns de árvores são:- Árvores binárias
- Cada nó tem no máximo dois filhos, um filho à esquerda e um filho à direita.
- Árvores binárias de busca (BST)
- Uma árvore binária em que todo filho à esquerda é menor que seu pai, e todo filho à direita é maior que seu pai.
Tries
Também conhecidas como árvores de prefixo, são usadas para armazenar conjuntos de strings, onde cada nó representa um caractere. Prefixos compartilhados são armazenados apenas uma vez, tornando-as eficientes para tarefas como autocompletar e verificação ortográfica. As operações de busca e inserção têm complexidade de tempo O(L), onde L é o comprimento da string.Filas de prioridade
Uma fila de prioridade é um tipo abstrato de dado em que cada elemento tem uma prioridade. Filas e pilhas consideram apenas a ordem de inserção, enquanto filas de prioridade consideram a prioridade dos elementos. Filas padrão seguem FIFO (First In First Out, primeiro a entrar, primeiro a sair) e pilhas seguem LIFO (Last In First Out, último a entrar, primeiro a sair). No entanto, em uma fila de prioridade, elementos com prioridade mais alta são atendidos antes daqueles com prioridade mais baixa, independentemente da ordem de inserção.Heaps
É uma estrutura de dados baseada em árvore especializada com uma propriedade muito específica chamada propriedade do heap. A propriedade do heap determina a relação entre nós pai e nós filho. Existem dois tipos de heaps:- Max-Heap
- O valor de cada nó pai é maior ou igual aos valores de seus filhos.
- O maior elemento está na raiz.
- Min-Heap
- O valor de cada nó pai é menor ou igual aos valores de seus filhos.
- O menor elemento está na raiz.
Exemplo do módulo Python heapq
import heapq
# Create empty heap
my_heap = []
# Insert elements
heapq.heappush(my_heap, 9)
heapq.heappush(my_heap, 3)
heapq.heappush(my_heap, 5)
print(my_heap) # [3, 9, 5]
# Remove smallest element
print(heapq.heappop(my_heap)) # 3
print(my_heap) # [5, 9]
# Push + Pop in one step
print(heapq.heappushpop(my_heap, 7)) # 5
print(my_heap) # [7, 9]
# Transform list into heap
nums = [5, 7, 3, 1]
heapq.heapify(nums)
Uso de prioridades
my_heap = []
heapq.heappush(my_heap, (3, "A"))
heapq.heappush(my_heap, (2, "B"))
heapq.heappush(my_heap, (1, "C"))
# Removes lowest number = highest priority
print(heapq.heappop(my_heap)) # (1, "C")
Introdução à programação dinâmica
- Definição: Programação dinâmica é uma técnica algorítmica que resolve problemas complexos dividindo-os em subproblemas mais simples e armazenando os resultados para evitar cálculos redundantes.
- Subproblemas sobrepostos: Os mesmos problemas menores aparecem várias vezes ao resolver o problema maior. Em vez de recalcular esses subproblemas repetidamente, armazenamos suas soluções.
- Subestrutura ótima: A solução ótima para o problema contém soluções ótimas para seus subproblemas. Isso significa que podemos construir a melhor solução combinando as melhores soluções para partes menores.
Soluções de programação dinâmica
- Memorização (abordagem de cima para baixo): A memorização armazena os resultados de chamadas de função caras e retorna o resultado em cache quando as mesmas entradas ocorrem novamente.
def climb_stairs_memo(n, memo={}):
"""Dynamic programming with memoization"""
# Check if we've already calculated this value
if n in memo:
return memo[n] # Return cached result - O(1) lookup!
# Base cases
if n <= 2:
return n
# Calculate once and store in memo for future use
memo[n] = climb_stairs_memo(n-1, memo) + climb_stairs_memo(n-2, memo)
return memo[n]
- Tabulação (abordagem de baixo para cima): A tabulação constrói a solução do zero, preenchendo uma tabela com soluções para subproblemas.
def climb_stairs_tabulation(n):
"""Dynamic programming with tabulation"""
if n <= 2:
return n
# Create array to store results for all steps from 0 to n
dp = [0] * (n + 1)
dp[1] = 1 # 1 way to reach step 1
dp[2] = 2 # 2 ways to reach step 2
# Build up the solution iteratively
for i in range(3, n + 1):
# Ways to reach step i = ways to reach (i-1) + ways to reach (i-2)
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
Aplicações reais usando programação dinâmica
- Otimização de rotas: sistemas de GPS usam algoritmos de programação dinâmica para buscar os caminhos mais curtos entre locais.
- Processamento de texto: corretores ortográficos e recursos de autocompletar frequentemente dependem de programação dinâmica para calcular distâncias de edição entre palavras.
- Modelagem financeira: estratégias de investimento e otimização de portfólio frequentemente empregam técnicas de programação dinâmica.
- Alocação de recursos: o problema da mochila e suas variantes aparecem em escalonamento, orçamento e gerenciamento de recursos.
Quando usar programação dinâmica
Você deve considerar usar programação dinâmica nos seguintes cenários:- O problema pode ser dividido em subproblemas que se sobrepõem.
- O problema apresenta subestrutura ótima.
- Uma solução recursiva ingênua envolveria cálculos repetidos.
- Você precisa otimizar a complexidade de tempo em detrimento da complexidade de espaço.