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

Variáveis e tipos

docs.scrimba.com

Todo programa precisa lembrar 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á verificando. Python usa variáveis para isso: nomes que você anexa a valores para poder usá-los em todo o seu programa.

Variáveis são referências nomeadas a valores. Python vincula um nome a um objeto no lado direito de = e permite que você o revindicule a 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 é permitido apontar.

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

Três linhas, três coisas que Python agora lembra. Para cada uma, Python funciona o valor no lado direito primeiro, depois o armazena sob o nome no lado esquerdo. Use esse nome depois e Python devolve o valor.

Cada linha cria uma vinculação: o nome na esquerda se refere ao objeto na 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 esse nome é visível, geralmente a função ou arquivo em que você está trabalhando). Python sempre funciona o lado direito completo antes de vincular qualquer coisa, e é exatamente por isso que a, b = b, a troca dois valores em uma linha: o lado direito é totalmente computado primeiro, depois ambos os nomes apontam para os resultados.

Armazenando um valor

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

python
city = "São Paulo"

city recebe "São Paulo". Você está dizendo ao Python: lembre-se de "São Paulo" e rotule-o 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 é 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

A atribuição aponta um nome para um objeto; nunca copia o valor em um novo contêiner. 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 revinculado para um novo objeto
print(id(a) == id(b))   # False
print(a)                # ainda "hello": revinculando 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 ignorar agora, mas morde com objetos mutáveis (aqueles que você pode alterar no lugar, como listas): aponte dois nomes para uma lista, altere através de qualquer nome, e a alteração 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 mantenha. É uma nota para ferramentas que leem seu código sem executá-lo (verificadores de tipo e seu editor), e Python a ignora enquanto o programa é executado:

python
name: str = "Maria"
score: int = 0
ratio: float = 0.85
JunoArmazenando um valor= não é "igual" da aula de maths, é "guarde esse valor sob esse nome". Altere quando quiser e Python mantém o mais novo. Sem declarar, sem setup, você nomeia e existe. Levei muito tempo para parar de complicar isso.
JunoArmazenando um valor= aponta um nome para um valor, e você pode reapontá-lo a qualquer hora. O nome é o rótulo, o valor é a coisa. Esse é 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 permanece. Lembre-se disso antes das listas aparecerem, ou você terá dois nomes silenciosamente compartilhando um.

Nomeando suas variáveis

Você escolhe o nome. Python tem algumas regras rígidas, e a comunidade segue convenções que vale a pena adotar desde o primeiro dia. Nomes claros tornam o código legível semanas depois. Nomes criptográficos causam dor.

Python impõe um pequeno conjunto de regras de sintaxe de identificador. Além disso, as convenções PEP 8 são o padrão de facto em todas as bases de código Python e ferramentas.

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 interpretador (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 todas as bases de código profissionais esperam. Ir contra ele principalmente cria atrito para quem ler seu código depois.

Regras que Python impõe:

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

Convenções que todos seguem (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ê se arrependerá disso em uma hora
x = "Maria"
tp = 49.99
b = True

Uma armadilha que vale a pena saber 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 quebará o built-in para o resto desse 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 desse escopo sem qualquer aviso. É um bug silencioso que pode ser doloroso de encontrar.

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

Sombrear um built-in significa fazer seu próprio nome que combina com um que Python já fornece (como list). Quando Python procura um nome, ele verifica seus nomes locais antes de seus próprios built-ins, então sua versão vence e o list real fica oculto a partir daí. Ainda é acessível como builtins.list, mas o código comum não o vê mais. Quanto a constantes, UPPER_SNAKE_CASE é apenas um sinal visual; Python vai felizmente deixá-lo reatribuir. Se você quer uma constante que uma ferramenta pode realmente impor, anote-a com typing.Final, que marca o nome como "não deve ser reatribuído" então verificadores de tipo o sinalizarão se você fizer.

JunoNomeando suas variáveis Letras, números, sublinhados, e comece com uma letra ou sublinhado. Fique com snake_case e você está pronto. Meu único erro de novato: não chame uma variável de list ou print. Python deixa, depois tudo fica estranho depois sem aviso nenhum.
JunoNomeando suas variáveissnake_case para nomes, UPPER_SNAKE_CASE para constantes, toda ferramenta espera. E não nomeie coisas list ou print, você vai clobberar o built-in silenciosamente.
JunoNomeando suas variáveis O interpretador mal impõe nomes, mas cada linter faz, então lutar contra snake_case só ganha você problemas. 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 você 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 é construído sobre eles.

Todo valor em Python é um objeto completo, até 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 direto 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 marcas de aspas, simples ou duplas. As aspas dizem ao Python que você quer dizer caracteres literais, não um nome de variável. Uma vez criada, uma string não pode ser alterada no lugar. O capítulo Strings cobre tudo que você pode fazer com elas.

python
player_name = "Maria"
city = "São Paulo"
message = 'Game over'

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

python
note = "It's a great day"
note = 'It\'s a great day'   # mesmo resultado, usando um escape

Strings contêm qualquer texto entre 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 performance: + 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 = "It's a great day"

Uma str é uma imutável sequência de pontos de código Unicode (imutável significa que nunca pode ser alterada após ser 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. Porque uma string não pode mudar, é hashable e pode ser usada como uma chave de dicionário ou membro do conjunto (um valor que nunca muda pode ser seguramente arquivado por seu conteúdo). Uma regra que você realmente usará sai disso: 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 que você não pode contar.

python
player_name = "Maria"
city = "São Paulo"
note = "It's a great day"
JunoTexto (str) Texto vai em aspas, simples ou duplas, você escolhe. Uma vez que existe você não pode alterá-lo no lugar, e está tudo bem. Qualquer coisa que pareça editar uma string na verdade devolve uma completamente nova.
JunoTexto (str) Strings são imutáveis. Nada as edita no lugar, você sempre recebe uma nova string. Tenha isso em mente no momento em que começar a encadear métodos.
JunoTexto (str) Uma execução imutável de Unicode, 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 inteiros. Eles podem ser tão grandes quanto você precisa; Python manipula números arbitrariamente grandes sem qualquer esforço especial da sua parte.

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

Inteiros são escritos sem aspas ou pontos decimais. Inteiros Python são precisão arbitrária: eles crescem para manter qualquer valor, diferentemente dos inteiros de 32 ou 64 bits de tamanho fixo em C ou Java. Sublinhados em literais numéricos são cosméticos e ignorados por Python.

python
score = 0
age = 28
population = 8_100_000_000

Duas coisas que valem a pena guardar. Primeiro, int do Python é precisão arbitrária: cresce para manter qualquer número inteiro que sua RAM possa caber, então não há overflow (o wrap-around ou erro que você pega em linguagens com inteiros de tamanho fixo) para projetar. 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 funcionar 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 grande quanto você quer sem overflow estranho. Esses sublinhados em 8_100_000_000 estão lá apenas para você ler.
JunoNúmeros inteiros (int) Ints são precisão arbitrária, então sem overflow para se preocupar. Sublinhados 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 é um não-problema. Um hábito que vale a pena manter: compare números com ==, não is. A identidade é um truque de cache, não confie nela.

Números decimais (float)

Qualquer número com um ponto decimal é um float. Eles funcionam como 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 obter um pequeno erro de arredondamento:

python
price = 4.99
temperature = 36.6

0.1 + 0.2   # 0.30000000000000004

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

Qualquer número com um ponto decimal se torna um float. Floats Python são dupla precisão: cerca de 15 a 17 dígitos significativos, armazenados em binário. Esse armazenamento binário é a cilada bem conhecida: 0.1 + 0.2 é 0.30000000000000004, não um bug de Python mas uma consequência de como binário representa decimais. Para dinheiro, ou em 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. É de onde 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ê verifique para igualdade exata. Alcance decimal.Decimal quando você precisa de aritmética base-10 exata, ou fractions.Fraction para proporções exatas. Ambas vêm com a biblioteca padrão do Python (as ferramentas agrupadas com Python), cobertas no capítulo Modules.

python
price = 4.99
temperature = 36.6
JunoNúmeros decimais (float) Um ponto decimal o torna um float, e eles são bons para coisas cotidianas. A cilada clássica que todo mundo pega uma vez: 0.1 + 0.20.30000000000000004. Não é um bug, isso é 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. Bom para a maioria das coisas de maths, 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 exato, fractions.Fraction para proporções.

Verdadeiro ou Falso (bool)

Algumas coisas estão ligadas ou desligadas. Python usa booleanos para isso: exatamente dois valores, True e False. Eles parecem menores neste estágio, mas toda condição e rama no 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 (o "não há valor aqui" do Python) todos se comportam como False. Tudo mais 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, contêineres vazios e None são falsy; tudo mais é truthy. Um detalhe útil: bool é uma subclasse de int, então True + True avalia a 2.

python
is_logged_in = True
has_errors = False

bool é construído em cima de int (ele subclassifica isso, significando que é uma tipo especializado 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), contêineres vazios ("", [], (), {}), None e False em si. Tudo mais é truthy. Suas próprias classes podem decidir sua veracidade definindo __bool__ ou __len__ (os métodos especiais "dunder", nomeados com sublinhados duplos, que Python chama quando precisa de uma resposta sim-ou-não). E porque 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ê escreverá. A parte legal: 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 vai surpreendê-lo em uma verificação de tipo um dia. Falsy é zeros, vazios e None. Objetos customizados pegam sua própria veracidade com __bool__ ou __len__.

Verificando e convertendo tipos

Quando você não tiver certeza do tipo de um valor, type() diz a você. 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 no seu próprio código, isinstance() é preferido: ele manipula herança, que comparações type() não fazem.

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

type(x) dá a você o tipo exato de x. isinstance(x, T) faz mais: ele caminha pelo MRO (a ordem de resolução de método, a lista ordenada de classes que Python procura acima da cadeia de herança, a linha de tipos pai a classe é construída, exposta como x.__class__.__mro__), então também retorna True para tipos pai. É por isso que isinstance(True, int) é True (um bool é um tipo de int) enquanto type(True) == int é False (uma verificação de correspondência exata). Em código real, alcance isinstance() como seu type guard, 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 função:

ChamadaResultado
str(42)"42"
int(3.9)3 (trunca, não arredonda)
float("3.14")3.14
int("3.14")ValueError: não é possível 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 determinado tipo. E Python não vai colar uma string e um número junto, então converta primeiro com str() ou int(). Todo mundo tropeça nisso uma vez.
JunoVerificando e convertendo tipos Alcance isinstance() sobre type() ==, ele 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() é seu type guard, ele segue a árvore de classes onde type(x) == T apenas corresponde exatamente. Conversões permanecem explícitas na propósito, int("3.14") preferiria levantar em vez de adivinhar, então passe por float primeiro.

Na prática

Todos os quatro tipos funcionando juntos em um pequeno script. As linhas de saída usam f-strings para embutir valores em texto: coloque f antes da aspas de abertura e envolva qualquer variável em {}. Python a substitui com o valor real da variável. Você aprenderá 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 coisa; Python não irá silenciosamente misturá-las para você.

Um bloco de configuração realista com todos os quatro tipos, constantes separadas do estado de runtime. A sintaxe f"..." é uma f-string: qualquer expressão dentro de {} é avaliada no tempo de execução e embutida 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 marcador padrão para "sem valor ainda". Seu tipo é NoneType e se comporta como falsy em condições. Use-o como 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 inline. Uma anotação registra o tipo que você espera que um nome mantenha. Existe para verificadores de tipo e seu editor (o IDE), e Python o ignora enquanto o programa é executado:

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 em Python 3.10: diz que o valor é uma string ou None. Em versões mais antigas você escreve a mesma coisa como Optional[str], importado do módulo typing construído. A forma str | None é aquela que prefere em Python moderno sempre que sua versão mínima permitir.