Skip to content
This page has been auto-translated and may contain errors.View in English

Variáveis e tipos

Todo programa precisa lembrar de coisas. Um quiz precisa do nome do jogador. Um jogo precisa da pontuação atual. Um script de clima precisa da cidade que você está consultando. Python usa variáveis para isso: nomes que você anexa a valores para poder usá-los em todo seu programa.

Variáveis são referências nomeadas a valores. Python vincula um nome a um objeto no lado direito de = e deixa você revincular em qualquer momento. O tipo vive no valor, não no nome.

Em Python uma variável é uma vinculação de nome: um nome que aponta para um objeto (um objeto é qualquer valor que Python mantém na memória, como uma string ou um número), nunca uma caixa rotulada que contém o valor em si. O tipo pertence ao objeto, não ao nome, então um nome pode apontar para uma str em uma linha e um int na próxima sem erro. Essa liberdade é chamada tipagem dinâmica: nada sobre o nome limita o que ele pode apontar.

python
player_name = "Maria"
score = 0
city = "São Paulo"

Três linhas, três coisas que o Python agora lembra. Para cada uma, Python calcula o valor à direita primeiro, depois o armazena sob o nome à esquerda. Use esse nome depois e Python devolve o valor para você.

Cada linha cria uma vinculação: o nome à esquerda se refere ao objeto à direita. Python avalia o lado direito primeiro, depois cria a vinculação.

Cada atribuição vincula um nome no escopo atual (a região do código onde aquele nome é visível, geralmente a função ou arquivo em que você está trabalhando). Python sempre calcula todo o lado direito antes de vincular qualquer coisa, o que é exatamente por que a, b = b, a troca dois valores em uma linha: o lado direito é totalmente calculado primeiro, depois ambos os nomes são apontados para os resultados.

Armazenando um valor

O sinal = confunde quase todo mundo vindo da aula de matemática. Em Python, = não significa "igual". Significa armazene este valor sob este nome:

python
city = "São Paulo"

city recebe "São Paulo". Você está dizendo ao Python: lembre-se de "São Paulo" e rotule como city.

Você pode substituir o valor de uma variável a qualquer momento. Python usa o mais recente:

python
score = 0
score = 10   # score agora é 10
score = 15   # score agora é 15

= é atribuição: vincula um nome a um objeto no escopo atual. Um atalho padrão para atualizar uma variável é a atribuição aumentada:

python
score = 0
score += 10   # mesmo que: score = score + 10
score *= 2    # mesmo que: score = score * 2

Você também pode vincular múltiplos nomes de uma vez:

python
x, y, z = 1, 2, 3
a = b = 0        # ambos começam em zero

Atribuição aponta um nome para um objeto; nunca copia o valor em um novo recipiente. Então dois nomes podem acabar apontando para o mesmo objeto:

python
a = "hello"
b = a
print(id(a) == id(b))   # True (ambos os nomes apontam para um objeto)

b = "world"             # b revincalado para um novo objeto
print(id(a) == id(b))   # False
print(a)                # ainda "hello": revincular b não afetou a

id() retorna a identidade de um objeto, um número único para aquele objeto enquanto existe, então dois ids iguais significam "literalmente o mesmo objeto", não dois objetos que acontecem ser iguais. A diferença entre apontar e copiar é tentadora de ignorar agora, mas morde com objetos mutáveis (aqueles que você pode mudar no lugar, como listas): aponte dois nomes para uma lista, mude-a através de um dos nomes, e a mudança aparece em ambos. Listas e dicts tornam isso concreto em capítulos posteriores.

Uma anotação de tipo registra o tipo que você espera que um nome contenha. É uma nota para ferramentas que leem seu código sem executá-lo (verificadores de tipo e seu editor), e o Python em si a ignora enquanto o programa está rodando:

python
name: str = "Maria"
score: int = 0
ratio: float = 0.85
JunoArmazenando um valor= não é "igual" da aula de matemática, é "guarde este valor sob este nome". Mude quando quiser e o Python mantém o mais novo. Sem declarações, sem configuração, você o nomeia e ele existe. Demorei muito tempo para parar de pensar demais nisso.
JunoArmazenando um valor= aponta um nome para um valor, e você pode reapontá-lo a qualquer momento. O nome é o rótulo, o valor é a coisa. É o truque todo.
JunoArmazenando um valor= não deixa um valor em uma caixa, vincula um nome a um objeto. Reatribuir apenas move o nome, o objeto antigo fica onde está. Lembre-se disso antes de listas aparecerem, ou você terá dois nomes compartilhando um silenciosamente.

Nomeando suas variáveis

Você escolhe o nome. Python tem algumas regras difíceis, e a comunidade segue convenções que valem a pena adotar desde o primeiro dia. Nomes claros tornam o código legível semanas depois. Nomes criptografados causam dor.

Python impõe um pequeno conjunto de regras de sintaxe de identificador. Além disso, as convenções do PEP 8 são o padrão de fato em toda base de código Python e ferramenta.

As regras que Python realmente impõe para um identificador (a palavra técnica para um nome) são mínimas. O resto é PEP 8, o guia de estilo oficial do Python. O intérprete (o programa que executa seu código) não o impõe, mas linters (ferramentas que sinalizam problemas de estilo e prováveis bugs), verificadores de tipo e toda base de código profissional o esperam. Ir contra ele principalmente cria atrito para quem ler seu código em seguida.

Regras que o Python impõe:

  • Letras, dígitos e underscores apenas. Sem espaços ou hífens.
  • Deve começar com uma letra ou underscore, nunca um dígito
  • Sensível a maiúsculas: score, Score, e SCORE são três variáveis diferentes

Convenções que todo mundo segue (PEP 8):

CoisaEstiloExemplo
Variáveis e funçõessnake_caseuser_name, total_price
ConstantesUPPER_SNAKE_CASEMAX_RETRIES, BASE_URL
ClassesPascalCaseUserAccount, DataLoader
python
# nomes claros, legíveis à primeira vista
user_name = "Maria"
total_price = 49.99
is_logged_in = True
MAX_RETRIES = 3

# você vai se arrepender destes em uma hora
x = "Maria"
tp = 49.99
b = True

Uma armadilha que vale a pena conhecer cedo: não nomeie uma variável após um built-in do Python como list, input, type, ou print. Python permite, mas você silenciosamente quebra o built-in para o resto daquele escopo e os erros resultantes são difíceis de rastrear.

Não sombreie os built-ins do Python. Atribuir a list, type, input, print, ou str sobrescreve o built-in para o resto daquele escopo sem nenhum aviso. É um bug silencioso que pode ser doloroso encontrar.

UPPER_SNAKE_CASE é uma convenção, não imposta. Python não o impedirá de reatribuir MAX_RETRIES = 99 mais tarde. É um sinal para outros desenvolvedores, nada mais.

Sombreamento de um built-in significa criar seu próprio nome que corresponde a um que o Python já fornece (como list). Quando Python procura um nome, verifica seus nomes locais antes de seus próprios built-ins, então sua versão vence e a list real fica oculta daquele ponto em diante. Ainda é acessível como builtins.list, mas código comum não a vê mais. Quanto às constantes, UPPER_SNAKE_CASE é apenas um sinal visual; Python felizmente deixará você reatribuí-la. Se você quer uma constante que uma ferramenta possa realmente impor, anote-a com typing.Final, que marca o nome como "não deve ser reatribuído" para que verificadores de tipo sinalizem se você fizer.

JunoNomeando suas variáveis Letras, números, underscores, e comece com uma letra ou underscore. Fique com snake_case e você está ótimo. Meu único erro de iniciante: não chame uma variável de list ou print. Python deixa, depois tudo fica estranho mais tarde sem nenhum aviso.
JunoNomeando suas variáveissnake_case para nomes, UPPER_SNAKE_CASE para constantes, toda ferramenta espera. E não nomeie coisas como list ou print, você vai calafetar o built-in silenciosamente.
JunoNomeando suas variáveis O intérprete mal impõe nomeação, mas todo linter faz, então lutar contra snake_case só ganha você atritos. A armadilha real é sombrear um built-in como list: quebra silenciosamente, e longe de onde você fez.

O que você pode armazenar

Python tem quatro tipos que você usará em quase todo programa. Python descobre qual tipo você quer pela forma como escreve o valor. Você nunca declara um tipo explicitamente.

Python infere o tipo a partir da sintaxe literal. Esses quatro tipos cobrem o espaço de valor fundamental; tudo mais na linguagem se constrói sobre eles.

Cada valor em Python é um objeto completo, mesmo um literal (um valor escrito direto no código, como 42 ou "hi"). Ser um objeto significa que o valor carrega seus próprios métodos (funções anexadas a ele), então "hi".upper() e (3).bit_length() funcionam diretamente no literal, sem nada para envolver ou desembrulhar primeiro. Você raramente tem que pensar sobre isso, e é o ponto. Os quatro tipos abaixo são aqueles que você alcança em quase todo programa.

Texto (str)

Qualquer texto vai dentro de aspas, simples ou duplas. As aspas dizem ao Python que você quer caracteres literais, não um nome de variável. Uma vez criada, uma string não pode ser mudada no lugar. O capítulo Strings cobre tudo que você pode fazer com elas.

python
player_name = "Maria"
city = "São Paulo"
message = 'Fim de jogo'

Se seu texto contém um apóstrofo, use aspas duplas para evitar ter que escapar:

python
note = "É um ótimo dia"
note = 'É um ótimo dia'   # mesmo resultado

Strings contêm qualquer texto em aspas simples ou duplas. Elas são imutáveis: nenhuma operação modifica uma string no lugar; cada transformação retorna uma nova. Isso importa para desempenho: + repetido dentro de um loop cria um novo objeto string a cada passo. O capítulo Strings cobre a alternativa eficiente.

python
player_name = "Maria"
city = "São Paulo"
note = "É um ótimo dia"

Uma str é uma sequência imutável de pontos de código Unicode (imutável significa que não pode ser mudada depois de criada; pontos de código são os caracteres em si, não os bytes brutos em que são armazenados), é por isso que len("café") é 4, não 5. Como uma string não pode mudar, é hashable e pode ser usada como uma chave de dicionário ou membro de conjunto (um valor que nunca muda pode ser seguramente arquivado pelo seu conteúdo). Uma regra que você realmente usará cai daí: compare strings com == (mesmos caracteres), nunca is (o mesmo objeto na memória), porque se duas strings iguais compartilham um objeto é um detalhe de implementação em que você não pode contar.

python
player_name = "Maria"
city = "São Paulo"
note = "É um ótimo dia"
JunoTexto (str) Texto vai entre aspas, simples ou duplas, sua escolha. Uma vez que existe você não pode mudá-la no lugar, e está tudo bem. Qualquer coisa que parece editar uma string na verdade lhe devolve uma completamente nova.
JunoTexto (str) Strings são imutáveis. Nada as edita no lugar, você sempre recebe uma nova string. Mantenha isso em mente o momento em que começar a encadear métodos.
JunoTexto (str) Uma sequência Unicode imutável, então len("café") é 4 e strings funcionam como chaves de dict. O bit que você realmente usará: compare com ==, nunca is.

Números inteiros (int)

Números inteiros vão sem aspas ou ponto decimal. Python os chama de inteiros. Eles podem ser tão grandes quanto você precisa; Python lida com números arbitrariamente grandes sem nenhum esforço especial de sua parte.

python
score = 0
age = 28
population = 8_100_000_000   # underscores são apenas para legibilidade

Inteiros são escritos sem aspas ou pontos decimais. Inteiros em Python são de precisão arbitrária: crescem para conter qualquer valor, ao contrário dos inteiros de 32 ou 64 bits de tamanho fixo em C ou Java. Underscores em literais numéricos são cosméticos e ignorados pelo Python.

python
score = 0
age = 28
population = 8_100_000_000

Duas coisas que valem a pena manter. Primeiro, o int do Python é precisão arbitrária: cresce para conter qualquer número inteiro que sua RAM possa caber, então não há overflow (o wrap-around ou erro que você bate em linguagens com inteiros de tamanho fixo) para projetar em torno. Segundo, compare números com == (valor igual), nunca is (o mesmo objeto). Se dois ints iguais são o mesmo objeto é um detalhe de implementação: CPython (o Python padrão) reutiliza inteiros pequenos, então id(1) == id(1) é True, mas isso silenciosamente para de valer para números maiores, então nunca construa sobre isso.

python
score = 0
age = 28
population = 8_100_000_000
JunoNúmeros inteiros (int) Números inteiros, sem aspas, sem ponto decimal. Melhor parte, ints do Python crescem tão grandes quanto você quiser sem overflow estranho. Esses underscores em 8_100_000_000 estão lá apenas para você poder ler.
JunoNúmeros inteiros (int) Ints são precisão arbitrária, então sem overflow para se preocupar. Underscores em números são cosméticos, use-os em qualquer coisa com muitos dígitos.
JunoNúmeros inteiros (int) Ints crescem até você ficar sem RAM, então overflow é uma não-questão. Um hábito que vale a pena manter: compare números com ==, não is. Identidade é um truque de caching, não apoie-se nela.

Números decimais (float)

Qualquer número com ponto decimal é um float. Funcionam conforme esperado para a maioria dos cálculos. Uma coisa a saber: alguns valores decimais não podem ser armazenados exatamente em binário, então você pode ter um pequeno erro de arredondamento:

python
price = 4.99
temperature = 36.6

0.1 + 0.2   # 0.30000000000000004

Para o trabalho do dia a dia isso raramente importa. Para cálculos financeiros onde frações de centavo contam, Python tem um módulo decimal que lida corretamente. Isso é coberto no capítulo Numbers.

Qualquer número com ponto decimal vira um float. Floats do Python são precisão dupla: cerca de 15 a 17 dígitos significativos, armazenados em binário. Aquele armazenamento binário é a pegadinha bem conhecida: 0.1 + 0.2 é 0.30000000000000004, não um bug do Python mas uma consequência de como o binário representa decimais. Para dinheiro, ou qualquer lugar onde decimais exatos importam, alcance o módulo decimal do Python, coberto no capítulo Numbers.

python
price = 4.99
temperature = 36.6

Floats são armazenados em binário (base 2), e a maioria das frações decimais, qualquer coisa cujo denominador não é uma potência de dois (como 1/10), não pode ser escrita exatamente em binário. É daí que 0.1 + 0.2 sair como 0.30000000000000004 vem. A regra que importa em produção: nunca use um float para dinheiro, ou para qualquer coisa que você verificará para igualdade exata. Alcance decimal.Decimal quando você precisar de aritmética exata em base-10, ou fractions.Fraction para razões exatas. Ambos vêm com a biblioteca padrão do Python (as ferramentas empacotadas com Python em si), coberto no capítulo Modules.

python
price = 4.99
temperature = 36.6
JunoNúmeros decimais (float) Um ponto decimal o torna um float, e eles estão tudo bem para o trabalho do dia a dia. A gotcha clássica que todo mundo bate uma vez: 0.1 + 0.20.30000000000000004. Não é bug, é binário. Para dinheiro, alcance decimal.Decimal.
JunoNúmeros decimais (float) Floats são binários, então alguns decimais não podem ser exatos, 0.1 + 0.2 não é bem 0.3. Está tudo bem para a maioria das matemáticas, nunca para dinheiro. Use decimal.Decimal quando tem que ser exato.
JunoNúmeros decimais (float) Floats derivam, é por isso que 0.1 + 0.2 parece quebrado. A regra: sem floats para dinheiro ou verificações de igualdade exata. decimal.Decimal para base-10 exata, fractions.Fraction para razões.

Verdadeiro ou Falso (bool)

Algumas coisas estão ligadas ou desligadas. Python usa booleanos para isso: exatamente dois valores, True e False. Parecem menores neste estágio, mas cada condição e ramificação em seu programa funciona em um booleano.

python
is_logged_in = True
has_errors = False

Python também trata certos valores como se fossem False quando usados em uma condição: 0, 0.0, "", e None (Python de "sem valor aqui") todos se comportam como False. Tudo o resto se comporta como True. Isso se torna útil no capítulo Control flow.

bool contém exatamente True ou False. É retornado por comparações e consumido por condições. Python tem um conjunto mais amplo de valores truthy e falsy: valores zero, recipientes vazios e None são falsy; tudo mais é truthy. Um detalhe útil: bool é uma subclasse de int, então True + True avalia para 2.

python
is_logged_in = True
has_errors = False

bool é construído em cima de int (ele subclassifica isso, significando que é uma espécie especializada de int), e True e False são os únicos dois objetos bool que jamais existem, valendo exatamente 1 e 0. Em uma condição, os valores falsy (aqueles que contam como false) são: zeros (0, 0.0), recipientes vazios ("", [], (), {}), None, e False em si. Tudo o resto é truthy. Suas próprias classes podem decidir sua veracidade definindo __bool__ ou __len__ (os métodos especiais "dunder", nomeados com underscores duplos, que Python chama quando precisa de uma resposta sim-ou-não). E como um bool é um int, isinstance(True, int) é True, que pode pegá-lo em código que verifica tipos.

python
is_logged_in = True
has_errors = False
JunoVerdadeiro ou Falso (bool) Dois valores, True e False, e estão atrás de cada if que você jamais escreverá. O bit divertido: 0, "", [] e None todos contam como False, tudo mais conta como True.
JunoVerdadeiro ou Falso (bool)bool é True/False de comparações. Python também tem truthy e falsy: coisas vazias, zero e None são falsy. É por isso que if my_list: lê tão bem.
JunoVerdadeiro ou Falso (bool)bool é secretamente um int, então isinstance(True, int) é True, que o surpreenderá em uma verificação de tipo um dia. Falsy é zeros, vazios e None. Objetos customizados escolhem sua própria veracidade com __bool__ ou __len__.

Verificando e convertendo tipos

Quando você não tem certeza qual tipo um valor é, type() o diz. Para verificar se um valor é um tipo específico, isinstance() é a ferramenta mais confiável:

python
print(type("hello"))   # <class 'str'>
print(type(42))        # <class 'int'>
print(type(3.14))      # <class 'float'>
print(type(True))      # <class 'bool'>

isinstance(42, int)    # True
isinstance("hi", str)  # True

type() retorna o tipo exato de um objeto. Para verificação de tipo em seu próprio código, isinstance() é preferido: lida com herança, que comparações de type() não.

python
print(type(42))          # <class 'int'>
isinstance(True, int)    # True   (bool é uma subclasse de int)
type(True) == int        # False  (correspondência exata apenas, sem subclasses)

type(x) dá a você o tipo exato de x. isinstance(x, T) faz mais: caminha pelo MRO (a ordem de resolução de método, a lista ordenada de classes que Python procura na cadeia de herança, a linha de tipos pais dos quais uma classe é construída, exposta como x.__class__.__mro__), então também retorna True para tipos pais. É por isso que isinstance(True, int) é True (um bool é uma espécie de int) enquanto type(True) == int é False (uma verificação de correspondência exata). Em código real, alcance isinstance() como seu tipo guarda, a verificação que confirma um valor é o tipo que você espera antes de usá-lo.

python
isinstance(True, int)    # True
type(True) == int        # False

Python não mistura tipos automaticamente. Concatenar uma string e um número levanta um TypeError:

python
score = 42
print("Your score is " + score)        # TypeError
print("Your score is " + str(score))   # funciona

Converta explicitamente usando o nome do tipo como uma função:

CallResultado
str(42)"42"
int(3.9)3 (trunca, não arredonda)
float("3.14")3.14
int("3.14")ValueError: não pode converter uma string decimal para int diretamente
int(float("3.14"))3 (converta para float primeiro, depois para int)
bool(0) / bool("")False
JunoVerificando e convertendo tipostype() diz o que algo é, isinstance() verifica se é um tipo dado. E Python não colará uma string e um número juntos, então converta primeiro com str() ou int(). Todo mundo tropeça nisso uma vez.
JunoVerificando e convertendo tipos Alcance isinstance() sobre type() ==, respeita herança. Conversões são sempre explícitas, então converta antes de concatenar uma string e um número.
JunoVerificando e convertendo tiposisinstance() é sua tipo guarda, segue a árvore de classe onde type(x) == T apenas corresponde exatamente. Conversões ficam explícitas propositalmente, int("3.14") preferiria levantar do que adivinhar, então vá através de float primeiro.

Na prática

Os quatro tipos funcionando juntos em um script pequeno. As linhas de saída usam f-strings para incorporar valores em texto: coloque f antes da aspas de abertura e envolva qualquer variável em {}. Python a substitui pelo valor real da variável. Você aprenderá sobre elas adequadamente no próximo capítulo.

python
player_name = "Maria"
level = 3
accuracy = 0.94
is_premium = True

print(f"{player_name} is on level {level} with {accuracy:.0%} accuracy.")
print(f"Premium account: {is_premium}")

Os tipos importam porque level + 1 funciona e player_name + 1 não. Cada variável contém exatamente uma espécie de coisa; Python não as misturará silenciosamente para você.

Um bloco de configuração realista com todos os quatro tipos, constantes separadas de estado de tempo de execução. A sintaxe f"..." é uma f-string: qualquer expressão dentro de {} é avaliada em tempo de execução e incorporada na saída. Coberto completamente no capítulo Output and input.

python
BASE_URL = "https://api.example.com"
MAX_RETRIES = 3
DEBUG = False

user_name = "Maria"
request_count = 0
last_response = None

request_count += 1
print(f"[{request_count}] {BASE_URL} | debug={DEBUG}")

None é o espaço reservado padrão para "sem valor ainda". Seu tipo é NoneType e se comporta como falsy em condições. Use-o como o padrão para variáveis que não são significativas até mais tarde no programa.

A mesma configuração, agora com anotações de tipo embutidas. Uma anotação registra o tipo que você espera que um nome contenha. Existe para verificadores de tipo e seu editor (o IDE), e Python a ignora enquanto o programa está rodando:

python
BASE_URL: str = "https://api.example.com"
MAX_RETRIES: int = 3
DEBUG: bool = False

user_name: str = "Maria"
request_count: int = 0
last_response: str | None = None

str | None é um tipo union, adicionado no Python 3.10: diz que o valor é ou uma string ou None. Em versões antigas você escreve a mesma coisa como Optional[str], importado do módulo typing embutido. A forma str | None é aquela a preferir em Python moderno sempre que sua versão mínima permite.