3  Tipos de Dados e Expressões

3.1 Introdução

Este capítulo apresenta os elementos fundamentais com que o Python trabalha: valores, tipos de dados e objetos, além de uma introdução prática a funções, variáveis e exploração interativa do ambiente. Ao final, o aluno deverá ser capaz de:

  • Identificar e usar os tipos básicos (int, float, str, bool) em programas Python.
  • Compreender que tudo é um objeto em Python e saber consultar métodos e atributos.
  • Manipular strings (concatenação, f-strings, escape, slicing e métodos úteis).
  • Converter entre tipos e lidar com entradas de usuário.
  • Usar dir() e help() para descobrir funcionalidades de objetos.

3.1.1 Pré-requisitos

Conhecimentos básicos de lógica e familiaridade com o interpretador Python (execução de scripts/linhas interativas). Neste capítulo usaremos principalmente funções nativas do Python.

3.2 Valores, Tipos e Objetos

Toda linguagem de programação precisa representar informações. Essas informações são chamadas de valores. Um valor pode ser um número, um texto, uma resposta lógica (verdadeiro ou falso), entre outros.

No entanto, o computador precisa saber como interpretar cada valor. O número 5 é diferente do texto “5”. Embora visualmente pareçam iguais, internamente são representados de forma distinta e permitem operações diferentes. É aqui que entra o conceito de tipo de dado.

Um tipo de dado define:

  • Como o valor é armazenado na memória;
  • Quais operações podem ser realizadas com ele;
  • Como o interpretador deve tratá-lo durante a execução do programa.

Em Python, todos os valores são implementados como objetos. Isso significa que cada valor possui:

  • Um tipo (sua categoria);
  • Um valor (a informação que representa);
  • Um conjunto de métodos (operações específicas que podem ser aplicadas a ele).

Essa característica torna o Python uma linguagem extremamente consistente e poderosa.

3.3 Breve Introdução às Funções

Em praticamente todas as linguagens de programação, o conceito de função é central. Funções permitem organizar o código, reutilizar instruções e estruturar programas de forma clara e modular. De maneira intuitiva, uma função pode ser entendida como uma ação — um “verbo” — que executa uma tarefa específica e, frequentemente, retorna um resultado.

Toda linguagem já possui um conjunto de funções pré-definidas, chamadas de funções nativas (ou built-in functions). Elas representam operações básicas que o computador já sabe realizar, como exibir algo na tela, converter tipos de dados ou calcular o tamanho de um objeto.

No nosso primeiro programa, utilizamos a função print. Essa função exibe informações na tela. Ela não imprime um texto fixo; imprime aquilo que for fornecido a ela.

print("Olá, Mundo")
Olá, Mundo

3.3.1 Argumentos

Um argumento é a informação que passamos para uma função para que ela saiba sobre qual valor deve operar. No exemplo anterior, "Olá, Mundo" é o argumento da função print.

Podemos pensar da seguinte forma:

  • A função é a ação;
  • O argumento é o objeto sobre o qual a ação será realizada.

3.3.2 Variáveis

Para que um programa seja dinâmico, precisamos armazenar valores. É aí que entram as variáveis. Uma variável é um nome que se refere a um valor armazenado na memória. Ela funciona como um rótulo que aponta para um objeto. Exemplo:

curso = "Métodos Computacionais"

Aqui, curso é a variável, "Métodos Computacionais" é o valor armazenado e = é o operador de atribuição. É importante destacar que, em Python, o símbolo = não significa igualdade matemática, mas sim atribuição.

Quando escrevemos, curso = "Métodos Computacionais", estamos dizendo: “Execute a função input, pegue o valor retornado por ela e armazene esse valor na variável curso.”

Exploraremos o conceito de funções com maior profundidade em aulas futuras, quando analisaremos sua definição formal, parâmetros, valores de retorno e sua importância na organização e modularização de programas.

3.4 Tipos Básicos

3.4.1 Inteiros (int)

O tipo int representa números inteiros: positivos, negativos ou zero. Do ponto de vista matemático, são os elementos do conjunto dos números inteiros.

x = 10
y = -3
print(x + y)
7

Inteiros permitem operações aritméticas tradicionais:

  • + soma
  • - subtração
  • * multiplicação
  • / divisão
  • // divisão inteira
  • % resto da divisão (módulo)
  • ** potência

O operador % é especialmente útil em programação. Por exemplo, para verificar se um número é par:

numero = 8
print(numero % 2 == 0)  # True
True

3.4.2 Pontos Flutuantes (float)

O tipo float representa números reais com parte decimal. Por exemplo:

x = 3.14
y = 2.5
print(x * y)
7.8500000000000005

Internamente, esses números são armazenados em formato de ponto flutuante binário, o que implica aproximações. Isso significa que certos valores aparentemente simples podem não ser representados de forma exata.

Por exemplo:

print(0.1 + 0.2)
0.30000000000000004

Isso não é erro do Python, mas uma limitação da representação binária de números decimais. Para lidar com isso, utilizamos, por exemplo, a função round:1

round(10 / 3, 2)
3.33

3.4.3 Strings (str)

Strings são sequências ordenadas de caracteres. No Python, qualquer valor delimitado por aspas simples ou aspas duplas é considerado um string.

nome = "Arthur"
print(nome)

curso = 'Economia'
print(curso)
Arthur
Economia

Podemos ainda utilizar uma sequência de três aspas duplas e escrever strings que percorram várias linhas. Isso é bastante útil na documentação de funções personalizadas, como veremos futuramente.

texto = """
Das Utopias

Se as coisas são inatingíveis...ora!
Não é motivo para não querê-las...
Que tristes os caminhos, se não fora
A presença distante das estrelas!

Mario Quintana
"""

print(texto)
print(type(texto))

Das Utopias

Se as coisas são inatingíveis...ora!
Não é motivo para não querê-las...
Que tristes os caminhos, se não fora
A presença distante das estrelas!

Mario Quintana

<class 'str'>

3.4.3.1 Formatação e o Problemas das Aspas

Observe como adicionar aspas como parte da sua string é um desafio. print("Olá, "amigo"") não funcionará e o interpretador retornará um erro. Geralmente, existem duas abordagens para corrigir isso.

Primeiro, você poderia simplesmente mudar as aspas para aspas simples.

print('Olá, "amigo"')
Olá, "amigo"

Uma abordagem mais comum consiste em utilizar o caractere de escape. Por exemplo:

print("Olá, \"amigo\"")
Olá, "amigo"

Nesse caso, a barra invertida (\) informa ao interpretador que o caractere imediatamente seguinte deve ser interpretado como parte literal da string — e não como um delimitador da string. Sem o escape, o Python entenderia a segunda aspa dupla como o encerramento da string, produzindo um erro de sintaxe.

O símbolo \ é chamado de caractere de escape (escape character). Ele tem duas funções principais:

  1. Permitir a inserção de caracteres especiais dentro de strings delimitadas pelo mesmo tipo de aspas (como \" ou \');
  2. Representar caracteres de controle, isto é, símbolos que não são visíveis, mas produzem efeitos específicos na saída.

Entre os caracteres de escape mais comuns estão:

  • \n (nova linha),
  • \t (tabulação),
  • \r (retorno de linha),
  • \b (backspace).
  • \\ (barra invertida)

Em termos gerais, o caractere de escape sinaliza ao interpretador que o próximo símbolo deve receber um tratamento especial, seja para ser exibido literalmente, seja para produzir um efeito específico na formatação do texto.

Uma maneira mais elegante e moderna de trabalhar com strings é por meio das f-strings (formatted string literals), introduzidas no Python 3.6.

nome = "Arthur"
print(f"Olá, {nome}")
Olá, Arthur

Observe o f antes das aspas em f"Olá, {nome}". Esse prefixo informa ao Python que se trata de uma string formatada. Isso permite inserir variáveis ou expressões diretamente dentro da string, entre chaves {}, tornando o código mais legível e natural. Em vez de concatenar:

print("Olá, " + nome)
Olá, Arthur

ou usar múltiplos argumentos:

print("Olá,", nome)
Olá, Arthur

a f-string permite escrever a mensagem praticamente como ela será exibida. As f-strings também permitem controlar a forma como números são exibidos.

valor = 20
raiz_quadrada = 20 ** 0.5
print(f"A raiz quadrada de {valor:d} é {raiz_quadrada:.2f}")
A raiz quadrada de 20 é 4.47

O comando :d indica que o valor deve ser tratado como inteiro (int). Já o comando :.2f indica que o valor deve ser exibido como número de ponto flutuante (float) com duas casas decimais.

3.4.3.2 Fatiamento de Strings (Slicing)

O fatiamento de string (slicing) permite que você “corte” uma string para obter uma subseção dela. A sintaxe básica utiliza colchetes e índices: string[início:fim].

  • Índice de Início: Onde o fatiamento começa (incluído).
  • Índice de Fim: Onde o fatiamento termina (excluído).

Assim como outras operações de sequência no Python, o fatiamento (slicing) utiliza indexação baseada em zero, onde o primeiro elemento está no índice 0. Pense no índice não como o número do caractere, mas como a distância (ou deslocamento) do início da string.

  • No índice 0, você percorreu 0 caracteres (está no início).
  • No índice 1, você saltou 1 caractere para chegar ao próximo.

Dica: Se uma string tem comprimento n, o último índice será sempre n−1. Imagine a string nome = "Python". Os índices são:

Letra P y t h o n
Índice 0 1 2 3 4 5
Negativo -6 -5 -4 -3 -2 -1
nome = "Python"

# Pega do índice 0 até o 2 (o 2 não entra)
print(nome[0:2])  # Saída: Py

# Se omitir o início, ele começa do zero
print(nome[:4])   # Saída: Pyth

# Se omitir o fim, ele vai até o último caractere
print(nome[2:])   # Saída: thon

# Pega os três últimos caracteres
print(nome[-3:])     # Saída: hon
# Pega todos caracteres exceto os dois últimos
print(nome[:-2])     # Saída: Pyth

Você também pode adicionar um terceiro parâmetro: string[início:fim:passo]. O passo determina quantos caracteres o Python deve pular. O Python também permite contar de trás para frente usando números negativos. Note que o -1 é sempre o último caractere.

telefone = "0123456789"

# Pega do 1 ao fim, pulando de 2 em 2
print(telefone[1:10:2])  # Saída: 13579

# Pega do início ao fim, pulando de 2 em 2
print(telefone[::2])  # Saída: 02468

# Um truque famoso: inverter uma string
print(nome[::-1])    # Saída: nohtyP

3.4.3.3 Métodos de Strings

As strings ilustram bem o conceito de objeto em Python, pois elas vêm acompanhadas de diversos métodos que permitem manipulá-las. Um método pode ser entendido como uma função que pertence a um objeto. Em termos práticos, trata-se de uma sequência de instruções encapsulada em um único comando, que pode receber argumentos e retorna um novo valor. A diferença fundamental é que o método é chamado a partir do próprio objeto, utilizando a notação com ponto: objeto.metodo().

No caso das strings, o Python já oferece, de forma nativa, vários métodos úteis para tratamento e limpeza de texto — algo essencial quando trabalhamos com entrada de dados fornecida pelo usuário. Por exemplo, é comum que o usuário digite espaços antes ou depois do nome. O método strip() remove automaticamente quaisquer espaços em branco à esquerda e à direita da string:

nome = "   Arthur       "
print(f"Olá, {nome}")

nome = nome.strip()
print(f"Olá, {nome}")
Olá,    Arthur       
Olá, Arthur

Após essa operação, mesmo que o usuário digite ” Arthur “, a variável nome armazenará apenas”Arthur”.

Observe que o método retorna uma nova string — ele não altera a string original diretamente. Esse comportamento é consequência do fato de que strings são imutáveis em Python.

Podemos ir além da simples remoção de espaços. Muitas vezes desejamos padronizar a forma como o texto é exibido, especialmente quando lidamos com nomes próprios ou títulos. Por exemplo, o método title() transforma a string para o chamado formato de título, colocando a primeira letra de cada palavra em maiúscula:

curso = "métodos computacionais em economia"

print(curso)
print(curso.title())
métodos computacionais em economia
Métodos Computacionais Em Economia

Já os métodos lower() e upper() convertem todos os caracteres para minúsculas e maiúsculas, respectivamente.

curso = "métodos computacionais em economia"

print(curso.lower())
print(curso.upper())
métodos computacionais em economia
MÉTODOS COMPUTACIONAIS EM ECONOMIA

Para dividir uma string em partes menores — chamadas substrings — com base em um padrão delimitador (como espaço, vírgula ou outro caractere), utilizamos o método split(). Esse método “quebra” a string sempre que encontra o delimitador especificado e retorna uma lista contendo os trechos resultantes.

No exemplo a seguir, o espaço " " é utilizado como critério de separação. Sempre que o Python encontra um espaço, ele divide o texto.

curso = "métodos computacionais em economia"

print(curso.split(" "))
['métodos', 'computacionais', 'em', 'economia']

O método replace() permite substituir ocorrências de um trecho de texto por outro dentro de uma string. Sua forma geral é: string.replace(antigo, novo[, quantidade]).

  • antigo: trecho que será substituído;
  • novo: texto que será inserido no lugar;
  • quantidade (opcional): número máximo de substituições a serem feitas.
texto = "Eu gosto de Java"

print(texto) # Saída: Eu gosto de Java
print(texto.replace("Java", "Python"))  # Saída: Eu gosto de Python
Eu gosto de Java
Eu gosto de Python

Observe dois pontos importantes:

  1. A string original (texto) não é alterada.
  2. O método retorna uma nova string, pois strings são imutáveis em Python.

Podemos controlar quantas ocorrências serão substituídas:

frase = "ha ha ha"
print(frase.replace("ha", "he", 2))
he he ha

Você pode aprender mais sobre strings e seus métodos na documentação oficial do Python sobre o tipo str

3.4.4 Booleanos (bool)

O tipo bool é utilizado para representar valores lógicos, isto é, valores que podem assumir apenas dois estados possíveis: True (Verdadeiro) ou False (Falso). Em Python, valores booleanos surgem com frequência como resultado de comparações ou expressões lógicas:

print(5 > 3)
print(8 < 2)
True
False

Esses valores serão fundamentais quando estudarmos estruturas de controle, como instruções condicionais (if, elif, else) e estruturas de repetição (while, for). Em programação, decisões dependem justamente de expressões que avaliam como verdadeiras ou falsas.

Algumas características importantes dos booleanos:

  1. Não levam aspas: “True” é uma string, não um booleano.
  2. Devem sempre começar com letra maiúscula (True, False).
  3. São um subtipo de inteiro em Python. Isso significa que: True equivale a numericamente a 1 e False equivale numericamente a 0. Essa característica pode ser útil em operações matemáticas e contagens:
resultado = True + True + False + True
print(resultado)
3

3.4.5 Listas

As listas são uma das estruturas de dados mais versáteis do Python. Elas são sequências ordenadas e mutáveis que podem armazenar elementos de qualquer tipo: números, strings, objetos ou até outras listas.

A forma mais comum de criar uma lista é colocar os elementos entre colchetes ([ ]). Um ponto importante é que listas: um inteiro, uma string, um float e até mesmo outra lista.

Uma lista dentro de outra lista é chamada de lista aninhada. Uma lista que não contém elementos é chamada de lista vazia.

numeros = [42, 123, 25]
cursos = ["Economia", "Administração", "Contabilidade", "Atuária"]
lista_mista = [42, "Economia", 3.14, [10, 20]] # Contém uma lista aninhada
lista_vazia = []

A função len pode ser usada para verificar o tamanho de uma lista, ou seja, quantos elementos ela contém. Note que a função len conta apenas os elementos da lista, não o número total de itens dentro de listas aninhadas:

print(len(numeros))
print(len(cursos))
print(len(lista_mista))
print(len(lista_vazia))
3
4
4
0

3.4.5.1 Operações com Listas

As listas suportam diversas operações, como: concatenação, repetição, verificação de existência de elementos, soma, obtenção do maior e menor valor, entre outras.

# Concatenação de listas
lista1 = [1, 2, 3]
lista2 = [4, 5, 6]
print(lista1 + lista2)

# Repetição de listas
print(lista1 * 3)

# Verificar se um elemento está ou não na lista
print("Economia" in cursos)
print("Direito" in cursos)
print("Matemática" not in cursos)

# Somar os elementos de uma lista de números
sum(numeros)

# Retornar o maior e o menor valor de uma lista de números
print(max(numeros))
print(min(numeros))
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 1, 2, 3, 1, 2, 3]
True
False
True
123
25

3.4.5.2 Fatiamento de Listas (Slicing)

Assim como strings, as listas também suportam o fatiamento (slicing), permitindo extrair uma subsequência de elementos. A sintaxe é a mesma: lista[início:fim:passo].

print(cursos[1:3])
print(cursos[:2])
print(cursos[2:])
print(cursos[-2:])

numeros = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

print(numeros[::2])
print(numeros[1::2])
print(numeros[::-1])
['Administração', 'Contabilidade']
['Economia', 'Administração']
['Contabilidade', 'Atuária']
['Contabilidade', 'Atuária']
[0, 2, 4, 6, 8]
[1, 3, 5, 7, 9]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

O acesso a listas aninhadas é feito usando colchetes várias vezes:

lista_aninhada = [1, 2, [10, 20, 30]]

print(lista_aninhada[2])
print(lista_aninhada[2][0])
print(lista_aninhada[2][1])
print(lista_aninhada[2][-1])
[10, 20, 30]
10
20
30

3.4.5.3 Mutabilidade das listas

Em Python, objetos podem ser mutáveis ou imutáveis: - Mutáveis: podem ser alterados após a criação, sem criar um novo objeto (exemplo: listas). - Imutáveis: não podem ser alterados após a criação; qualquer “mudança” cria um novo objeto (exemplo: strings, inteiros, floats).

Strings são objetos imutáveis: não é possível modificar seus caracteres diretamente. Qualquer alteração resulta em uma nova string. Por exemplo, tentar modificar o primeiro caractere de uma string gera um erro:

string = "economia"
string[0] = "E"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[31], line 2
      1 string = "economia"
----> 2 string[0] = "E"

TypeError: 'str' object does not support item assignment

Ao contrário das strings, listas são mutáveis, ou seja, seus elementos podem ser alterados diretamente, sem criar um novo objeto. No exemplo abaixo, modificamos os elementos da lista disciplinas de forma direta — a lista permanece o mesmo objeto na memória, mas seu conteúdo é atualizado:

disciplinas = ["micro", "macro", "econometria", "estatística"]

print(disciplinas)

disciplinas[0] = "Microeconomia"
disciplinas[1] = "Macroeconomia"

print(disciplinas)
['micro', 'macro', 'econometria', 'estatística']
['Microeconomia', 'Macroeconomia', 'econometria', 'estatística']

Note que, ao copiar uma lista, ambas as variáveis passam a apontar para o mesmo objeto na memória. Como listas são mutáveis, qualquer alteração feita em uma delas afeta também a outra, pois ambas compartilham a mesma referência.

lista_original = [1, 2, 3]
lista_copia = lista_original

lista_original[1] = 42

print(lista_original)
print(lista_copia)
[1, 42, 3]
[1, 42, 3]

Esse comportamento não ocorre com tipos imutáveis, como inteiros (int). Ao copiar um inteiro para outra variável, cada uma passa a referenciar um valor independente. Alterar uma delas não afeta a outra, pois um novo objeto é criado na memória. Por exemplo:

a = 10
b = a
a = 20
print(a)  # 20
print(b)  # 10
20
10

3.4.5.4 Métodos de Listas

Listas possuem diversos métodos que permitem adicionar, remover, reorganizar e buscar elementos de forma eficiente. Os principais métodos são: append, extend, remove, insert, reverse e index.

Vamos ilustrar esses métodos com um exemplo divertido: criar uma lista com os resultados possíveis para uma corrida de Mario Kart!

Mario Kart
resultados = ["Mario", "Luigi"]

# O método append adiciona um novo elemento ao final da lista
resultados.append("Princesa Peach")
resultados.append("Yoshi")
resultados.append("Koopa Troopa")
resultados.append("Toad")

print(resultados)

# Podemos adicionar mais de um elemento por vez
resultados.append(["Bowser", "Donkey Kong"])

# O método remove busca na lista e remove a primeira ocorrência do elemento
resultados.remove(["Bowser", "Donkey Kong"])

# O método extend adiciona cada elemento de uma lista ao final de outra
resultados.extend(["Bowser", "Donkey Kong"])

print(resultados)
resultados.remove("Bowser")

# O método insert adiciona um elemento em uma posição específica da lista
print(resultados)
resultados.insert(0, "Bowser")

print(resultados)

# O método index retorna o índice da primeira ocorrência do elemento especificado
print(resultados.index("Mario"))

# O método reverse inverte a ordem dos elementos da lista
resultados.reverse()
print(resultados)
['Mario', 'Luigi', 'Princesa Peach', 'Yoshi', 'Koopa Troopa', 'Toad']
['Mario', 'Luigi', 'Princesa Peach', 'Yoshi', 'Koopa Troopa', 'Toad', 'Bowser', 'Donkey Kong']
['Mario', 'Luigi', 'Princesa Peach', 'Yoshi', 'Koopa Troopa', 'Toad', 'Donkey Kong']
['Bowser', 'Mario', 'Luigi', 'Princesa Peach', 'Yoshi', 'Koopa Troopa', 'Toad', 'Donkey Kong']
1
['Donkey Kong', 'Toad', 'Koopa Troopa', 'Yoshi', 'Princesa Peach', 'Luigi', 'Mario', 'Bowser']

3.4.6 Tuplas

Tuplas são sequências ordenadas de elementos, semelhantes às listas, mas com uma diferença fundamental: tuplas são imutáveis. Isso significa que, após sua criação, não é possível alterar, adicionar ou remover elementos de uma tupla. Essa característica torna as tuplas úteis para representar dados que não devem ser modificados, como coordenadas, datas ou pares de valores.

Para criar uma tupla, basta separar os valores por vírgula, com ou sem parênteses. Podemos, ainda, criar tuplas usando a função tuple(), que converte outros tipos de dados em tuplas.:

# Tupla de três números
valores = (10, 20, 30)
print(type(valores))

# Tupla de strings
cidades = "São Paulo", "Belo Horizonte", "Recife"
print(type(cidades))

# Tupla mista
dados = ("Economia", 2026, 3.14)

t = tuple()
print(t)

t = tuple('economia')
print(t)

t2 = tuple([1, 2, 3])
print(t2)

t3 = tuple((4, 5, 6))
print(t3)
<class 'tuple'>
<class 'tuple'>
()
('e', 'c', 'o', 'n', 'o', 'm', 'i', 'a')
(1, 2, 3)
(4, 5, 6)

Cuidado: colocar um valor entre parênteses não cria uma tupla. Para criar uma tupla com um único elemento, é necessário incluir uma vírgula após o elemento, com ou sem parênteses. Isso indica ao Python que se trata de uma tupla. Essa sintaxe é importante para evitar erros ao manipular dados, especialmente em situações de desempacotamento ou funções que retornam tuplas.

t1 = ('a')
print(type(t1))

t2 = 'a',
print(type(t2))

t3 = ('a',)
print(type(t3))
<class 'str'>
<class 'tuple'>
<class 'tuple'>

3.4.6.1 Operações com Tuplas

A maioria dos operadores de listas também funciona com tuplas. Por exemplo, podemos aplicar as seguintes operações: - indexação (t[i]); - fatiamento (t[i:j:k]); - obtenção de comprimento (len(t)); - concatenação (t1 + t2); - replicação (t * n) - obtenção do valor mínimo (min(t)) e máximo (max(t))

t = tuple('economia')

# Indexação: o operador colchetes ([]) acessa um elemento
print(t[0])

# Fatiamento: operador slice seleciona uma parte da tupla
print(t[1:4])

# Número de elementos na tupla
print(len(t))

# Concatenação: o operador + contatena tuplas
print(t + ('F', 'E', 'A'))

# Repetição: o operador * repete a tupla
print(t * 2)

# Valor mínimo e máximo funciona para strings (ordem alfabética)
print(min(t))
print(max(t))

# Para tuplas numéricas:
numeros = (42, 123, 25)
print(min(numeros))
print(max(numeros))
e
('c', 'o', 'n')
8
('e', 'c', 'o', 'n', 'o', 'm', 'i', 'a', 'F', 'E', 'A')
('e', 'c', 'o', 'n', 'o', 'm', 'i', 'a', 'e', 'c', 'o', 'n', 'o', 'm', 'i', 'a')
a
o
25
123

Ao contrário das listas, tuplas são imutáveis: seus elementos não podem ser alterados após a criação. Qualquer tentativa de modificar uma tupla usando o operador de colchetes resultará em um TypeError.

# Tupla imutável
t = (1, 2, 3)
t[0] = 99  # TypeError: 'tuple' object does not support item assignment
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[39], line 3
      1 # Tupla imutável
      2 t = (1, 2, 3)
----> 3 t[0] = 99  # TypeError: 'tuple' object does not support item assignment

TypeError: 'tuple' object does not support item assignment

Tuplas também não possuem métodos para modificar o conteúdo, como append ou remove.

t.remove(2) # AttributeError: 'tuple' object has no attribute 'remove'
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[40], line 1
----> 1 t.remove(2) # AttributeError: 'tuple' object has no attribute 'remove'

AttributeError: 'tuple' object has no attribute 'remove'

3.4.6.2 Atribuição de Tuplas

A atribuição de tuplas em Python permite distribuir os valores de uma tupla diretamente para múltiplas variáveis, tornando o código mais claro e prático. A ideia básica é atribuir os valores de uma tupla (à direita do operador de atribuição =) para uma tupla de variáveis (à esquerda do =). É fundamental que o número de variáveis à esquerda seja igual ao número de valores à direita do =; caso contrário, ocorre um ValueError.

De forma mais geral, se o lado esquerdo de uma atribuição for uma tupla, o lado direito pode ser qualquer tipo de sequência — string, lista ou tupla.

# Atribuição de tuplas
a, b = 1, 2
a, b

# Para dividir um endereço de e-mail em um nome de usuário e um domínio
email = 'aluno@usp.br'
usuario, dominio = email.split('@')
usuario, dominio

print("Usuário:", usuario)
print("Domínio:", dominio)
Usuário: aluno
Domínio: usp.br

No exemplo a seguir, ocorre o desempacotamento dos valores da tupla aluno, atribuindo cada valor a uma variável correspondente do lado esquerdo. Isso torna o código mais legível, facilita o acesso individual aos dados e evita erros de indexação. Esse recurso é muito útil para funções que retornam múltiplos valores, pois permite capturar todos os resultados de forma elegante e organizada, tornando o código mais claro e fácil de manter.

aluno = (1234567, "Adam Smith", 20, "Bacharelado em Ciências Econômicas")
nusp, nome, idade, curso = aluno

print(f"NUSP: {nusp}")
print(f"Nome: {nome}")
print(f"Idade: {idade}")
print(f"Curso: {curso}")
NUSP: 1234567
Nome: Adam Smith
Idade: 20
Curso: Bacharelado em Ciências Econômicas

Atribuição de tuplas é útil quando você deseja trocar os valores de duas variáveis.

x = 10
y = 20
print(f"Antes da troca: x = {x}, y = {y}")

x, y = y, x # troca os valores de x e y
print(f"Depois da troca: x = {x}, y = {y}")
Antes da troca: x = 10, y = 20
Depois da troca: x = 20, y = 10

3.4.6.3 Função zip()

A função zip é utilizada para combinar duas ou mais sequências (listas, tuplas, etc.) em pares, formando uma nova sequência de tuplas. Se os iteráveis tiverem tamanhos diferentes, o zip para quando o mais curto terminar. É ideal para combinar dados ou criar dicionários. Para separar listas agrupadas, use o operador *.

# Combinando listas
nomes = ["Ana", "Bia", "Caio"]
idades = [25, 30, 22]

dados = zip(nomes, idades)
print(list(dados))

# Separando listas agru[adas]
coordenadas = [(-23.5, -46.6), (-22.9, -43.2), (-21.7, -41.3)]

latitude, longitude = zip(*coordenadas)

print(f"Latitude: {latitude}")
print(f"Longitude: {longitude}")
[('Ana', 25), ('Bia', 30), ('Caio', 22)]
Latitude: (-23.5, -22.9, -21.7)
Longitude: (-46.6, -43.2, -41.3)

3.4.7 Conjuntos

Até aqui, estudamos tipos de dados como str, list e tuple, que representam coleções sequenciais. Nessas estruturas, a ordem dos elementos é definida e cada item pode ser acessado por meio de um índice numérico, começando em zero.

Agora, vamos explorar dois tipos fundamentais da linguagem: o set (conjunto) e o dict (dicionário). Ambos ampliam as possibilidades de manipulação de dados em Python, permitindo operações mais eficientes e adequadas a diferentes contextos.

Conjuntos (sets) são estruturas de dados mutáveis, que armazenam elementos únicos e não ordenados. Isso significa que:

  • Não permitem elementos duplicados;
  • Não garantem ordem de armazenamento;
  • Não suportam indexação nem slicing.

Em Python, conjuntos são definidos por valores separados por vírgulas dentro de chaves {}. No exemplo a seguir, observe que, mesmo repetindo “economia”, o conjunto mantém apenas uma ocorrência.

# Criando conjuntos
s = {"economia", "administração", "contabilidade", "economia"}
print(s)  # O segundo "economia" será descartado automaticamente

# Conjunto vazio: DEVE usar set(), pois {} cria um dicionário vazio
vazio = set()
{'administração', 'contabilidade', 'economia'}

3.4.7.1 Operações e Métodos

Embora os conjuntos sejam mutáveis (podemos adicionar e remover elementos), seus itens precisam ser imutáveis (por exemplo: str, int, float, tuple). Listas e dicionários não podem ser elementos de um set.

Após a criação de um conjunto, não é possível alterar seus elementos. No entanto, é possível adicionar novos elementos usando o método add(). Note que, se o elemento já estiver presente no conjunto, ele não será adicionado novamente.

# Adicionar elementos usando o método add()
s.add("atuária")
print(s)

# Se o elemento estiver presente, o método add() não fará nada
s.add("economia")
print(s)
{'administração', 'contabilidade', 'economia', 'atuária'}
{'administração', 'contabilidade', 'economia', 'atuária'}

Para adicionar múltiplos elementos de uma vez, utilizamos o método update().

# Adicionar múltiplos elementos usando o método update()
s.update(['EAE', 'EAD', 'EAC'])
print(s)
{'contabilidade', 'economia', 'EAD', 'EAC', 'atuária', 'administração', 'EAE'}

Para remover elementos do conjunto, podemos usar os métodos remove() ou discard(). A diferença é que remove() gera um erro se o elemento não estiver presente, enquanto discard() não.

# Remover elementos usando o método remove()
s.remove("EAE")
print(s)

# Isso causará um erro, pois "EAE" já foi removido
s.remove("EAE")

# Isso não causará um erro, mesmo se "EAE" não estiver presente
s.discard("EAE")
{'contabilidade', 'economia', 'EAD', 'EAC', 'atuária', 'administração'}
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[48], line 6
      3 print(s)
      5 # Isso causará um erro, pois "EAE" já foi removido
----> 6 s.remove("EAE")
      8 # Isso não causará um erro, mesmo se "EAE" não estiver presente
      9 s.discard("EAE")

KeyError: 'EAE'

Mesmo não sendo indexados, conjuntos permitem verificação eficiente de existência usando o operador in. A operação de busca em conjuntos é muito eficiente, sendo uma das grandes vantagens dessa estrutura.

# Verificar se um elemento está presente usando o operador in
print('economia' in s)
print('matemática' in s)
True
False

Os conjuntos oferecem diversos métodos que facilitam operações clássicas da teoria dos conjuntos. Entre as principais operações, destacam-se:

  • União: .union() ou operador |.
  • Interseção: .intersection() ou operador &.
  • Diferença: .difference() ou operador -.
  • Diferença simétrica: .symmetric_difference() ou operador ^.

Operações com conjuntos

A união de dois conjuntos resulta em um novo conjunto contendo todos os elementos presentes em pelo menos um dos conjuntos. Em Python, essa operação pode ser realizada com o método .union() ou com o operador |.

s1 = {1, 2, 3}
s2 = {3, 4, 5}

# União usando o método union()
s_uniao = s1.union(s2)
print(s_uniao)

# União usando o operador |
s_uniao_operador = s1 | s2
print(s_uniao_operador)
{1, 2, 3, 4, 5}
{1, 2, 3, 4, 5}

A interseção de dois conjuntos resulta em um novo conjunto contendo apenas os elementos que estão presentes em ambos. Em Python, essa operação pode ser feita com o método .intersection() ou com o operador &.

# Interseção usando o método intersection()
s_intersecao = s1.intersection(s2)
print(s_intersecao)

# Interseção usando o operador &
s_intersecao_operador = s1 & s2
print(s_intersecao_operador)
{3}
{3}

A diferença entre dois conjuntos resulta em um novo conjunto contendo apenas os elementos que estão no primeiro conjunto e não aparecem no segundo. Essa operação é útil para identificar itens exclusivos de um grupo em relação ao outro.

# Diferença usando o método difference()
s_diferenca = s1.difference(s2)
print(s_diferenca)

# Diferença usando o operador -
s_diferenca_operador = s1 - s2
print(s_diferenca_operador)
{1, 2}
{1, 2}

A diferença simétrica entre dois conjuntos resulta em um novo conjunto contendo todos os elementos que pertencem a apenas um dos conjuntos, ou seja, exclui os elementos que estão em ambos. É útil para identificar itens exclusivos de cada grupo, eliminando os que são compartilhados.

# Diferença simétrica usando o método symmetric_difference()
s_diferenca_simetrica = s1.symmetric_difference(s2)
print(s_diferenca_simetrica)

# Diferença simétrica usando o operador ^
s_diferenca_simetrica_operador = s1 ^ s2
print(s_diferenca_simetrica_operador)
{1, 2, 4, 5}
{1, 2, 4, 5}

Uma das aplicações mais comuns dos conjuntos (sets) é a remoção de dados duplicados. Para obter elementos distintos, basta converter a lista original utilizando a função set(). Se necessário, o resultado pode ser transformado novamente em lista com list(). Esta abordagem é altamente eficiente, embora não garanta a preservação da ordem original dos elementos.

nomes = ["Ana", "João", "Ana", "Maria"]
nomes_unicos = list(set(nomes))
print(nomes_unicos)  # Saída: ['Maria', 'Ana', 'João'] (a ordem não é garantida)
['Maria', 'Ana', 'João']

3.4.8 Dicionários

Diferentemente das listas, os dicionários são uma coleção não sequencial. Em vez de usar índices numéricos, eles organizam os dados por meio de associações entre chaves e valores. Assim, podemos pensar em um dicionário como um mapeamento: cada chave aponta para um valor.

  • Chave (key): identificador único
  • Valor (value): dado associado à chave

Para dominar os dicionários, precisamos ter em mente três regras:

  1. Unicidade das Chaves: Cada chave é única. Se você tentar atribuir um novo valor a uma chave já existente, o valor antigo será sobrescrito.
  2. Imutabilidade das Chaves: As chaves não podem ser alteradas após sua criação. Por isso, devem ser de um tipos imutáveis: str, int, float, tuple (desde que a tupla só contenha itens imutáveis). Os tipos list ou outros dict não podem ser chaves.
  3. Flexibilidade dos Valores: Os valores podem ser de qualquer tipo, inclusive listas ou outros dicionários.

A forma mais comum de declarar um dicionário é utilizando chaves {}. Para declarar um dicionário já preenchido, utilizamos o formato chave: valor, separando os pares por vírgulas dentro das chaves {}. Também é possível criar dicionários usando a função dict().

# Criando um dicionário vazio usando chaves
alunos = {}
print(type(alunos))

# Criando um dicionário com elementos
alunos = {
    'nome': 'Arthur',
    'idade': 20,
    'curso': 'Economia'
}

# Criando um dicionário usando a função dict()
alunos = dict()
print(type(alunos))

# Criando um dicionário com elementos
alunos = dict(
    nome = 'Arthur',
    idade = 20,
    curso = 'Economia'
)

print(alunos)
<class 'dict'>
<class 'dict'>
{'nome': 'Arthur', 'idade': 20, 'curso': 'Economia'}

Outra forma comum de construir dicionários é a partir de uma lista de tuplas, onde cada tupla atua como um par chave-valor. Além disso, podemos associar duas listas distintas utilizando a função zip() em conjunto com dict(): a primeira lista fornece as chaves e a segunda, os valores correspondentes.

# Usando uma lista de tuplas para criar um dicionário
alunos = dict([
    ('nome', 'Arthur'),
    ('idade', 20),
    ('curso', 'Economia')
])

print(alunos)

# Usando dict() e zip() para criar um dicionário a partir de duas listas
chaves = ['nome', 'idade', 'curso']
valores = ['Arthur', 20, 'Economia']
alunos = dict(zip(chaves, valores))

print(alunos)
{'nome': 'Arthur', 'idade': 20, 'curso': 'Economia'}
{'nome': 'Arthur', 'idade': 20, 'curso': 'Economia'}

3.4.8.1 Acessando e Modificando Itens

Ao contrário das listas e tuplas, que usam índices numéricos para acessar ou modificar elementos (ex: alunos[0]), nos dicionários o acesso, criação ou alteração de valores é feito diretamente pela chave, usando colchetes. Quando tentamos acessar o valor de uma chave que não existe no dicionário, o Python gera uma exceção do tipo KeyError.

# Acessar um valor
print(f"Nome: {alunos['nome']}")

# Modificar um valor
alunos["idade"] = 30
print(f"Idade: {alunos['idade']}")

# Adicionar um novo par chave-valor
alunos["disciplina"] = ["Métodos Computacionais", "Microeconomia", "Macroeconomia"]
print(f"Disciplina: {alunos['disciplina']}")

# Acessar um valor inexistente (gera um erro)
print(f"Nome: {alunos['cidade']}")
Nome: Arthur
Idade: 30
Disciplina: ['Métodos Computacionais', 'Microeconomia', 'Macroeconomia']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[57], line 13
     10 print(f"Disciplina: {alunos['disciplina']}")
     12 # Acessar um valor inexistente (gera um erro)
---> 13 print(f"Nome: {alunos['cidade']}")

KeyError: 'cidade'

Para verificar se uma chave está presente em um dicionário, utilizamos o operador in. Por outro lado, para checar se uma chave não está presente, usamos o operador not in.

print('nome' in alunos)
print(f"A chave 'nome' está presente? {'nome' in alunos}")

print('nome' not in alunos)
print(f"A chave 'nome' não está presente? {'nome' not in alunos}")
True
A chave 'nome' está presente? True
False
A chave 'nome' não está presente? False

Para remover uma entrada (par chave-valor) de um dicionário, utilizamos a instrução del seguida do nome do dicionário e da chave entre colchetes. Se a chave não existir, será gerado um erro do tipo KeyError.

# Remover uma entrada do dicionário
del alunos['disciplina']

3.4.8.2 Métodos de Dicionários

Os dicionários possuem métodos eficientes para a manipulação e consulta de dados. Embora o acesso via colchetes (dict[chave]) seja o mais comum, ele interrompe a execução do código com um KeyError caso a chave não seja encontrada. Como alternativa mais robusta, o método .get() permite consultar chaves de forma segura, retornando um valor padrão (ou None) quando a chave está ausente, o que garante maior estabilidade à aplicação.

# Retorna o valor associado à chave ou valor padrão se a chave não existir
print(f"Nome: {alunos.get('nome')}")

print(f"Cidade: {alunos.get('cidade')}")

print(f"Cidade: {alunos.get('cidade', 'Chave não encontrada')}")
Nome: Arthur
Cidade: None
Cidade: Chave não encontrada

O método .keys() retorna uma visão das chaves do dicionário. O resultado é um objeto do tipo dict_keys, semelhante a uma lista, contendo todas as chaves presentes no dicionário.

# Retorna uma visão das chaves do dicionário
chaves = alunos.keys()
print(chaves)
print(type(chaves))

# Transformar a visão das chaves em uma lista
lista_chaves = list(alunos.keys())
print(f"Lista de chaves: {lista_chaves}")
dict_keys(['nome', 'idade', 'curso'])
<class 'dict_keys'>
Lista de chaves: ['nome', 'idade', 'curso']

O método .values() retorna uma visão dos valores armazenados no dicionário, ou seja, todos os dados associados às suas respectivas chaves. O resultado é um objeto do tipo dict_values, semelhante a uma lista, contendo os valores presentes no dicionário.

# Retorna uma visão dos valores do dicionário
valores = alunos.values()
print(valores)
print(type(valores))

lista_valores = list(valores)
print(f"Lista de valores: {lista_valores}")
dict_values(['Arthur', 30, 'Economia'])
<class 'dict_values'>
Lista de valores: ['Arthur', 30, 'Economia']

Já o método .items() permite acessar simultaneamente todas as chaves e valores de um dicionário, retornando uma visão composta por tuplas, onde cada tupla contém:

  • A chave do dicionário como primeiro elemento;
  • O valor associado a essa chave como segundo elemento.

Essa abordagem é útil para percorrer ou manipular pares chave-valor de forma eficiente, especialmente em operações de iteração e processamento de dados.

# Retorna uma visão dos pares chave-valor do dicionário
itens = alunos.items()
print(itens)
print(type(itens))

lista_itens = list(itens)
print(f"Lista de itens: {lista_itens}")
dict_items([('nome', 'Arthur'), ('idade', 30), ('curso', 'Economia')])
<class 'dict_items'>
Lista de itens: [('nome', 'Arthur'), ('idade', 30), ('curso', 'Economia')]

O método .pop() remove e retorna o valor da chave especificada:

# Adicionar um novo par chave-valor
alunos['disciplina'] = "Métodos Computacionais"
print(alunos)

# Remove e retorna o valor da chave especificada
alunos.pop('disciplina')
{'nome': 'Arthur', 'idade': 30, 'curso': 'Economia', 'disciplina': 'Métodos Computacionais'}
'Métodos Computacionais'

O método .update() atualiza o dicionário, inserindo ou sobrescrevendo dados:

alunos = {
    'nome': 'Pedro',
    'idade': 20,
    'curso': 'Administração'
}

print(alunos)

# Atualiza o elemento de chave 'nome'
alunos.update({'nome': 'Maria', 'idade': 30, 'curso': 'Economia'})
print(alunos)

# Cria os elementos de chave-valor
alunos.update({'disciplina': ['Métodos Computacionais', 'Microeconomia']})
print(alunos)
{'nome': 'Pedro', 'idade': 20, 'curso': 'Administração'}
{'nome': 'Maria', 'idade': 30, 'curso': 'Economia'}
{'nome': 'Maria', 'idade': 30, 'curso': 'Economia', 'disciplina': ['Métodos Computacionais', 'Microeconomia']}

3.4.8.3 Lista de Dicionários

Uma lista de dicionários é uma estrutura de dados robusta, ideal para representar coleções de registros de forma similar a uma tabela de banco de dados. Nesse modelo, a lista atua como a tabela e cada dicionário funciona como uma linha (ou tupla) de dados (ex: [{'id': 1}, {'id': 2}]). Embora ofereça a flexibilidade de chaves distintas em cada item, é comumente utilizada para organizar dados homogêneos. Abaixo, veremos como estruturar uma lista de estudantes, onde cada elemento armazena as informações de um aluno:

# Criando uma lista de dicionários
estudantes = [
    {'nome': 'Danilo', 'idade': 20, 'curso': 'Economia'},
    {'nome': 'Arthur', 'idade': 22, 'curso': 'Economia'},
    {'nome': 'Maria', 'idade': 21, 'curso': 'Administração'},
    {'nome': 'João', 'idade': 23, 'curso': 'Contabilidade'},
]

print(estudantes)

# Acessar o terceiro dicionário da lista
print(estudantes[2])
print(f"Nome: {estudantes[2]['nome']}")
print(f"Idade: {estudantes[2]['idade']}")
print(f"Curso: {estudantes[2]['curso']}")
[{'nome': 'Danilo', 'idade': 20, 'curso': 'Economia'}, {'nome': 'Arthur', 'idade': 22, 'curso': 'Economia'}, {'nome': 'Maria', 'idade': 21, 'curso': 'Administração'}, {'nome': 'João', 'idade': 23, 'curso': 'Contabilidade'}]
{'nome': 'Maria', 'idade': 21, 'curso': 'Administração'}
Nome: Maria
Idade: 21
Curso: Administração

3.5 Explorando o Python

Programar não significa memorizar todos os métodos e funções da linguagem. Parte essencial do aprendizado é desenvolver autonomia para explorar e descobrir recursos por conta própria. Além da documentação oficial online, o próprio Python oferece ferramentas internas que permitem investigar objetos, tipos e funções diretamente no interpretador.

A função dir() funciona como um mapa de possibilidades. Ela lista todos os atributos e métodos disponíveis para um objeto ou tipo de dado. Por exemplo, para descobrir o que pode ser feito com strings:

dir(str)
['__add__',
 '__class__',
 '__contains__',
 '__delattr__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__getnewargs__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__iter__',
 '__le__',
 '__len__',
 '__lt__',
 '__mod__',
 '__mul__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__rmod__',
 '__rmul__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'capitalize',
 'casefold',
 'center',
 'count',
 'encode',
 'endswith',
 'expandtabs',
 'find',
 'format',
 'format_map',
 'index',
 'isalnum',
 'isalpha',
 'isascii',
 'isdecimal',
 'isdigit',
 'isidentifier',
 'islower',
 'isnumeric',
 'isprintable',
 'isspace',
 'istitle',
 'isupper',
 'join',
 'ljust',
 'lower',
 'lstrip',
 'maketrans',
 'partition',
 'removeprefix',
 'removesuffix',
 'replace',
 'rfind',
 'rindex',
 'rjust',
 'rpartition',
 'rsplit',
 'rstrip',
 'split',
 'splitlines',
 'startswith',
 'strip',
 'swapcase',
 'title',
 'translate',
 'upper',
 'zfill']

Isso responde rapidamente à pergunta: “Será que existe um método pronto para fazer isso?”. Em vez de procurar manualmente na internet, você pode verificar diretamente no interpretador.

Enquanto dir() mostra o que existe, a função help() explica como usar. Se você esquecer como funciona o método strip(), por exemplo:

help(str.strip)
Help on method_descriptor:

strip(self, chars=None, /)
    Return a copy of the string with leading and trailing whitespace removed.
    
    If chars is given and not None, remove characters in chars instead.

O interpretador exibirá:

  • A descrição do método;
  • Sua assinatura (quais argumentos aceita);
  • O que ele retorna;
  • Eventuais observações técnicas.

Isso permite compreender não apenas que um método existe, mas como utilizá-lo corretamente.

3.6 Conclusão

Neste capítulo, exploramos os pilares essenciais do Python: dos tipos básicos de dados (int, float, str, bool) às estruturas de dados fundamentais (lists, sets, dict). Mais do que operar e indexar valores, compreendemos a natureza de objeto na linguagem — onde cada dado possui tipo, identidade e métodos próprios. Este fundamento é a base para dominar estruturas complexas e o controle de fluxo. Agora, estamos prontos para avançar rumo às iterações, expandindo significativamente o alcance e a inteligência dos nossos programas.

3.7 Exercícios

  1. Considere as duas listas abaixo. Escreva um programa que as converta em um dicionário em que os itens de keys correspondam às chaves do dicionários e os itens de values os valores.

    keys = ['Ten', 'Twenty', 'Thirty']
    values = [10, 20, 30]
  2. Considere as atribuições abaixo. Sem executar o código, indique o tipo de cada variável. Explique por que a expressão a + d gera um erro. Reescreva-a de forma que a soma aritmética seja realizada corretamente e retorne o valor desejado \(20\).

    a=10
    b=3
    c=10.0
    d=1.25
    e='10'
  3. Considere o string Universidade de São Paulo. Escreva um código que acesse (i) o primeiro caractere; (ii) o último caractere (sem contar manualmente o tamanho do string); (iii) o nome da cidade utilizando fatiamento.

  4. Discorra sobre as principais diferenças entre listas e tuplas. A partir da sua resposta, discuta sobre qual das estruturas é mais indicada para armazenar (i) as notas obtidas por um aluno em determinadas disciplinas e (ii) as coordenadas geográficas de uma cidade (latitude e longitude).


  1. Você pode aprender mais sobre a função round na documentação oficial do Python.↩︎