Todo programa manipula informação. Para isso, a linguagem precisa de uma forma de armazenar e identificar dados na memória do computador. Em Python, esse mecanismo é simples e direto — mas esconde decisões de design que vale entender desde o início.
O que é uma Variável?
Uma variável é um nome que aponta para um valor armazenado na memória. Em Python, você não precisa declarar o tipo da variável antecipadamente — basta atribuir um valor:
nome = "Ricardo"
idade = 35
altura = 1.78
ativo = True
Python descobre o tipo automaticamente. Isso se chama tipagem dinâmica — o tipo está associado ao valor, não ao nome da variável.
Diferente de Java ou C, onde você escreveria:
// Java
String nome = "Ricardo";
int idade = 35;
Em Python, o nome da variável é apenas um rótulo. Você pode inclusive reatribuí-lo a um tipo diferente (embora isso seja má prática):
x = 10
x = "agora sou texto" # válido, mas evite
Tipos de Dados Fundamentais
int — Números inteiros
ano = 2024
populacao = 215000000
temperatura_negativa = -15
print(type(ano)) # <class 'int'>
Python suporta inteiros de tamanho arbitrário — não há limite de bits como em C ou Java.
numero_gigante = 10 ** 100 # 1 googol — funciona perfeitamente
float — Números decimais
preco = 49.90
pi = 3.14159
gravidade = -9.8
print(type(preco)) # <class 'float'>
Atenção ao problema clássico de ponto flutuante:
>>> 0.1 + 0.2
0.30000000000000004
Isso não é bug do Python — é uma limitação do padrão IEEE 754, presente em praticamente todas as linguagens. Para cálculos financeiros, use o módulo decimal — e repare nas aspas, porque elas são a parte que importa:
from decimal import Decimal
resultado = Decimal("0.1") + Decimal("0.2")
print(resultado) # 0.3
str — Texto
Strings podem ser delimitadas por aspas simples ou duplas — o resultado é idêntico:
saudacao = "Olá, mundo!"
linguagem = 'Python'
Para textos com múltiplas linhas, use três aspas:
mensagem = """
Linha 1
Linha 2
Linha 3
"""
Strings em Python são imutáveis — uma vez criadas, não podem ser alteradas. Operações sobre strings sempre geram uma nova string.
nome = "ricardo"
print(nome.upper()) # RICARDO
print(nome.capitalize()) # Ricardo
print(len(nome)) # 7
print(nome[0]) # r
print(nome[-1]) # o
bool — Booleanos
ligado = True
desligado = False
print(type(ligado)) # <class 'bool'>
Em Python, True e False são escritos com inicial maiúscula. Booleanos são subclasse de int — True vale 1 e False vale 0:
>>> True + True
2
>>> False * 100
0
NoneType — Ausência de valor
None representa a ausência de valor. É usado quando uma variável existe mas ainda não tem conteúdo definido:
resultado = None
if resultado is None:
print("Ainda não foi calculado.")
Conversão entre Tipos
Python não converte tipos automaticamente (exceto em casos muito específicos). A conversão explícita é feita com funções:
# str para int
numero = int("42")
print(numero + 8) # 50
# int para str
texto = str(100)
print("Valor: " + texto) # Valor: 100
# str para float
preco = float("19.99")
print(preco * 2) # 39.98
# int para float
x = float(5)
print(x) # 5.0
Tentar converter um valor inválido gera um erro:
int("abc") # ValueError: invalid literal for int()
Verificando o Tipo de uma Variável
x = 3.14
print(type(x)) # <class 'float'>
print(isinstance(x, float)) # True
print(isinstance(x, int)) # False
Boas Práticas na Nomeação de Variáveis
Python adota o estilo snake_case para variáveis e funções — palavras em minúsculo separadas por underscore:
# Correto
nome_completo = "Ricardo Matos"
total_de_alunos = 120
preco_unitario = 9.99
# Evite
NomeCompleto = "Ricardo Matos" # reservado para classes
nomecompleto = "Ricardo Matos" # difícil de ler
n = "Ricardo Matos" # pouco descritivo
Nomes de variáveis não podem começar com número e não podem ser palavras reservadas da linguagem (if, for, class, return, etc.).
O ponto que sustenta tudo o que veio nesta parte é a frase que parece apenas didática: em Python o nome é um rótulo, e o tipo mora no valor. Daí decorre a conversão explícita que a linguagem exige, decorre o isinstance ser mais confiável que comparar o resultado de type, e decorre a surpresa de dois nomes apontarem para a mesma lista. Quem entende a variável como uma caixa que guarda um valor vai tropeçar nas três coisas; quem a entende como uma etiqueta colada num objeto não tropeça em nenhuma.
A aritmética de ponto flutuante merece a mesma atenção. O 0.30000000000000004 não é defeito do Python nem curiosidade de sala de aula: é o que acontece quando se guarda um número decimal em base dois, e vale para toda linguagem que usa IEEE 754. O decimal resolve, desde que o valor entre como texto — construir um Decimal a partir de um float apenas carrega o erro para dentro do módulo que deveria evitá-lo.
Fontes e leituras recomendadas
- Tipos nativos do Python — https://docs.python.org/3/library/stdtypes.html
- PEP 8 — Guia de estilo do Python — https://peps.python.org/pep-0008/
- Módulo decimal — https://docs.python.org/3/library/decimal.html
- IEEE 754 (ponto flutuante) — https://floating-point-gui.de/
- MATTHES, Eric. Python Crash Course. 3. ed. No Starch Press, 2023. Cap. 2.
- LUTZ, Mark. Learning Python. 5. ed. O'Reilly Media, 2013. Cap. 4–5.
Exercícios
Exercício 1
O artigo recomenda o módulo decimal para cálculo financeiro e mostra Decimal("0.1") + Decimal("0.2"). Um colega escreve Decimal(0.1) + Decimal(0.2), sem as aspas, e reclama que "o decimal também erra". Ele está certo?
Ver resposta
✓ Resposta: O módulo está certo; a construção é que está errada. Com aspas, o Decimal recebe o texto "0.1" e representa exatamente um décimo. Sem aspas, o que chega ao construtor já é um float — o literal 0.1 foi convertido para binário antes de o decimal ver qualquer coisa, e o que ele recebe é o valor que de fato existe na memória. Dá para ver a olho nu: Decimal(0.1) imprime 0.1000000000000000055511151231257827021181583404541015625. O módulo está sendo fiel, reproduzindo o erro que já vinha pronto, e Decimal(0.1) + Decimal(0.2) devolve 0.3000000000000000166533453694. A regra é curta e vale para todo sistema que lida com dinheiro: um valor decimal nunca deve passar por float em nenhum ponto do caminho. Ele entra como texto vindo do formulário, viaja como Decimal, e é gravado numa coluna DECIMAL do banco — nunca FLOAT nem DOUBLE. Se em algum trecho alguém escreve float(valor) para "facilitar uma conta", o erro entra ali e não sai mais. Vale saber também que a alternativa comum, guardar centavos como inteiro, funciona pelo mesmo motivo: inteiro em Python é exato e não tem limite de tamanho.
Exercício 2
O artigo afirma que os booleanos são subclasse de int, e mostra True + True resultando em 2. Isso parece uma curiosidade inofensiva. Descreva um caso em que essa herança produz um defeito real.
Ver resposta
✓ Resposta: O caso mais silencioso é o dicionário. Como True == 1 e os dois têm o mesmo hash, eles são a mesma chave: escrever {1: "um", True: "verdadeiro"} produz um dicionário de um único item, e {1: "a"}[True] devolve "a" sem erro nenhum. Num código que usa identificadores numéricos vindos de um banco e, em algum ponto, deixa passar um booleano — uma flag lida de uma coluna, o retorno de uma comparação —, o valor simplesmente sobrescreve o do identificador 1, e o sintoma aparece muito longe da causa. Há um segundo caso, este útil: sum([True, True, False]) devolve 2, e é por isso que sum(1 for x in lista if condicao(x)) e sum(condicao(x) for x in lista) contam a mesma coisa — comportamento em que muito código se apoia de propósito. E há a armadilha da verificação de tipo: isinstance(True, int) devolve True, então uma função que valida a entrada com isinstance(valor, int) aceita True como se fosse número. Se a distinção importa, o teste tem de ser type(valor) is int, que é justamente o caso em que comparar o tipo diretamente é mais correto do que usar isinstance.
Exercício 3
O artigo insiste que "o nome da variável é apenas um rótulo". Você escreve a = [1, 2], depois b = a, e em seguida b.append(3). O que acontece com a, e por que o mesmo raciocínio não vale para x = 10 seguido de y = x?
Ver resposta
✓ Resposta: a passa a valer [1, 2, 3]. A atribuição b = a não copiou a lista: colou um segundo rótulo no mesmo objeto, e a is b é True. O append altera esse objeto no lugar, e quem estiver olhando por qualquer um dos nomes vê a mudança. Com x = 10 e y = x os dois nomes também apontam para o mesmo objeto, mas inteiro é imutável — não existe operação que altere o número 10 no lugar. Ao escrever y += 1, o que acontece não é modificar; é criar o objeto 11 e reapontar y para ele, deixando x intocado. Ou seja: a regra é a mesma para tudo, e é a mutabilidade do objeto que muda o que se observa. Em Python, imutáveis são int, float, str, bool, tuple e frozenset; mutáveis são list, dict, set e a maioria dos objetos que você mesmo define. A consequência prática mais cara aparece quando se passa uma lista para uma função: ela recebe o mesmo objeto, e qualquer alteração feita lá dentro é visível fora. Quem quer trabalhar sobre uma cópia precisa pedir por ela — b = a.copy() para um nível, copy.deepcopy(a) quando há estrutura aninhada.
Exercício 4
O artigo destaca que Python tem inteiros de tamanho arbitrário e mostra 10 ** 100 funcionando. Isso significa que Python não perde precisão com números grandes?
Ver resposta
✓ Resposta: Não — a garantia vale para int, e só. O 10 ** 100 é exato, com os 101 dígitos todos corretos, e 10 ** 100 + 1 é de fato diferente de 10 ** 100. Já 1e100 é um float, com os mesmos 64 bits e a mesma precisão limitada de sempre: 1e100 + 1 == 1e100 devolve True, porque o 1 é pequeno demais para aparecer na representação. E as duas formas nem sequer são o mesmo número — 1e100 == 10 ** 100 devolve False. O detalhe que pega na prática é que basta um ponto flutuante na expressão para o resultado inteiro virar float e perder a exatidão: a divisão / sempre devolve float, mesmo quando o resultado é redondo, e é por isso que existe a divisão inteira //. Duas outras conversões enganam pelo mesmo motivo. int(42.9) devolve 42, porque trunca em vez de arredondar. E round não faz o arredondamento da escola: usa a regra do dígito par, então round(2.5) é 2 e round(3.5) é 4 — perfeitamente correto segundo o padrão, e uma surpresa garantida para quem confere uma soma na mão.
Exercício 5
Você lê uma planilha exportada em CSV e converte a coluna de quantidade com int(valor). O código funciona com a maior parte dos arquivos e levanta ValueError em alguns. Quais são as causas prováveis e como tratá-las?
Ver resposta
✓ Resposta: Há quatro causas comuns, e só uma delas é "dado inválido". A primeira é o decimal disfarçado: int("42.0") levanta ValueError, mesmo o valor sendo inteiro — a função aceita a representação de um inteiro, não a de um número que por acaso é redondo. Planilha exporta quantidade como 42.0 com frequência, e a correção é int(float(valor)), ciente de que isso trunca. A segunda é o campo vazio: célula em branco chega como "", que também é ValueError e normalmente deveria virar None ou zero, conforme a regra do negócio — decisão que precisa ser tomada, não deixada para o acaso. A terceira é formatação numérica: separador de milhar ("1.234" ou "1,234") e símbolo de moeda vêm colados no número, e aqui mora uma armadilha regional séria, porque "1.234" significa mil e duzentos e trinta e quatro numa planilha em português e um vírgula duzentos e trinta e quatro numa em inglês — adivinhar dá erro por um fator de mil. A quarta é o caractere invisível: espaço em volta o int tolera sozinho, mas BOM no começo do arquivo e espaço não separável vindo da web, não. O tratamento certo não é envolver tudo num try que engole a exceção: é normalizar o que se sabe normalizar, e registrar qual linha e qual valor falharam, porque numa importação de milhares de registros a mensagem invalid literal for int() sem o contexto não ajuda ninguém a consertar a planilha.