Quando começamos a programar em Python, é comum encontrar linhas como:
idade = 20resultado = 10 + 5print(nome.upper())
À primeira vista, parecem apenas linhas simples de código. Mas dentro delas existem diferentes expressões.
Entender o que é uma expressão ajuda a interpretar melhor o código Python, compreender operadores, trabalhar com listas e dicionários, chamar funções e, mais adiante, entender recursos como compreensões, geradores, yield e await.
Neste artigo, vamos começar pelo básico e avançar gradualmente.
Observação: os exemplos foram pensados para Python 3.12. A documentação oficial classifica átomos, literais, identificadores e várias outras construções como partes da sintaxe de expressões. Python documentation
O que são expressões em Python?
Uma expressão é uma combinação de elementos que Python consegue avaliar para produzir um valor.
Por exemplo:
10 + 5
Essa expressão é avaliada e produz:
15
Outro exemplo:
idade > 18
Se idade tiver o valor 20, o resultado será:
True
Uma expressão também pode ser muito simples:
42
Nesse caso, o resultado é simplesmente o número 42.
Podemos pensar em uma expressão como algo que responde à pergunta:
“Qual valor isso representa?”
Veja alguns exemplos:
10
Resultado:
10
10 + 5
Resultado:
15
"Python"
Resultado:
Python
10 > 3
Resultado:
True
Essa ideia será importante durante todo o artigo.
Átomos: os elementos básicos de uma expressão
Na terminologia da linguagem Python, átomos são os elementos mais básicos das expressões.
Entre os átomos estão identificadores, literais e determinadas construções entre parênteses, colchetes ou chaves. Python documentation
Por exemplo:
42
nome
"Olá"
[1, 2, 3]
São exemplos de construções que podem participar de expressões.
True, False, None e ...
Python possui alguns valores especiais que aparecem diretamente na linguagem:
TrueFalseNone...
True representa verdadeiro:
ativo = True
False representa falso:
ativo = False
None representa a ausência de um valor:
resultado = None
Já ... representa o objeto Ellipsis:
valor = ...
Para quem está começando, o mais importante é reconhecer esses elementos e saber que eles também podem aparecer em expressões.
Variáveis, nomes e identificadores
Quando escrevemos:
idade = 25
idade é um identificador usado como nome.
Depois disso, podemos utilizar esse nome em uma expressão:
idade + 5
O Python procura o objeto associado ao nome idade e avalia a expressão.
Por exemplo:
idade = 25nova_idade = idade + 5print(nova_idade)
Resultado:
30
Se quiser entender melhor a relação entre variáveis e tipos de dados em Python, este é um bom momento para consultar o artigo sobre tipos de variáveis em Python.
Identificador não é o mesmo que valor
Observe:
nome = "Tiago"
Aqui:
nomeé o identificador;"Tiago"é um literal;"Tiago"é o valor associado ao nome.
Quando usamos:
nome
o Python consegue avaliar o nome e obter o objeto associado a ele.
E o __spam?
Python também possui uma regra especial chamada name mangling, utilizada principalmente dentro de classes.
Por exemplo:
class Pessoa: def __init__(self): self.__nome = "Tiago"
Um nome com dois sublinhados no início, como __nome, pode sofrer uma transformação interna relacionada ao nome da classe.
Isso não significa simplesmente “variável privada” no sentido de outras linguagens. É melhor pensar que Python utiliza essa convenção para reduzir conflitos acidentais entre nomes em classes e subclasses.
Para um iniciante, basta reconhecer que __nome possui um comportamento diferente de um identificador comum.
Literais em Python
Um literal é uma representação direta de um valor no código.
Veja:
10
3.14
"Olá"
True
b"Python"
Esses valores aparecem diretamente no código-fonte.
Python possui literais numéricos, de strings e de bytes, entre outros elementos definidos pela linguagem. Python documentation
Literais inteiros
10
100
-50
Literais de ponto flutuante
3.14
10.5
Literais de texto
"Python"
'Olá, mundo!'
Literais de bytes
b"Python"
A diferença fundamental é:
nome
é um nome/identificador.
Enquanto:
"nome"
é um literal de string.
Tipos de dados usados em expressões
Diversos tipos de dados podem participar de expressões.
Entre os mais conhecidos estão:
intfloatcomplexstrbyteslisttuplesetdictrange
Por exemplo:
idade = 25altura = 1.75nome = "Tiago"
Podemos utilizar esses valores em expressões:
idade + 5
altura * 2
nome + " Sousa"
Coleções também podem participar:
numeros = [10, 20, 30]numeros[0]
O resultado será:
10
Operadores em Python
Os operadores são símbolos ou palavras que permitem realizar operações sobre valores.
Por exemplo:
10 + 5
Temos:
10→ operando;+→ operador;5→ operando.
O resultado é:
15
Operadores aritméticos
Os principais operadores aritméticos são:
| Operador | Função | Exemplo |
|---|---|---|
+ |
adição | 10 + 5 |
- |
subtração | 10 - 5 |
* |
multiplicação | 10 * 5 |
/ |
divisão | 10 / 5 |
// |
divisão inteira | 10 // 3 |
% |
resto da divisão | 10 % 3 |
** |
potência | 10 ** 2 |
@ |
multiplicação de matrizes | A @ B |
Por exemplo:
10 + 5
resulta em:
15
Já:
10 % 3
resulta em:
1
porque 1 é o resto da divisão de 10 por 3.
Operadores unários
Os operadores unários trabalham com um único valor.
-10
+10
~10
Por exemplo:
numero = 10print(-numero)
Resultado:
-10
O operador ~ realiza uma operação de complemento de bits em inteiros:
~10
Seu comportamento pode parecer estranho no começo, então não é necessário dominá-lo para compreender as expressões mais comuns.
Operadores de deslocamento
Python também possui:
<<>>
Eles realizam deslocamentos de bits.
Por exemplo:
4 << 1
e:
8 >> 1
Esses operadores são mais comuns em situações que envolvem manipulação de bits.
Para quem está começando, basta reconhecer que eles também fazem parte dos operadores disponíveis em expressões Python.
Operadores bit a bit
Python possui ainda:
&^|
Eles representam operações bit a bit:
&→ AND;^→ XOR;|→ OR.
Por exemplo:
5 & 3
Essas operações trabalham sobre a representação binária dos números.
Embora sejam importantes em determinados tipos de programação, não são necessárias para escrever a maioria dos programas introdutórios.
Comparações
Expressões também podem comparar valores.
Veja:
10 > 5
O resultado será:
True
Outros operadores de comparação incluem:
<><=>===!=
Por exemplo:
idade = 20idade >= 18
Resultado:
True
== e !=
O operador == verifica se dois valores são iguais:
10 == 10
Resultado:
True
Já:
10 != 5
resulta em:
True
porque os valores são diferentes.
is e is not
Também existem:
isis not
Eles verificam identidade de objetos, e não simplesmente igualdade de valores.
Por isso, não devemos substituir automaticamente:
==
por:
is
Para comparar valores, normalmente usamos ==.
in e not in
Esses operadores verificam pertencimento:
"Python" in ["Python", "Java", "C"]
Resultado:
True
Outro exemplo:
10 not in [1, 2, 3]
Resultado:
True
Essas expressões são especialmente úteis em condições.
Por exemplo:
nome = "Tiago"if nome in ["Tiago", "Ana", "Carlos"]: print("Nome encontrado")
Se você quiser ver esse tipo de expressão funcionando dentro de uma estrutura de repetição, o artigo sobre while em Python e um sistema de login simples complementa bem este conteúdo.
Coleções como expressões
Listas, conjuntos e dicionários também podem participar de expressões.
Uma lista:
[10, 20, 30]
Um conjunto:
{10, 20, 30}
Um dicionário:
{"nome": "Tiago", "idade": 25}
Uma tupla:
(10, 20, 30)
Essas estruturas podem ser usadas diretamente ou combinadas com outras expressões.
Por exemplo:
numeros = [10, 20, 30]numeros[1]
Resultado:
20
Compreensões
As compreensões permitem criar coleções de maneira compacta.
Uma list comprehension simples:
quadrados = [x ** 2 for x in range(5)]
Resultado:
[0, 1, 4, 9, 16]
A ideia é:
“Para cada
xemrange(5), coloquex ** 2na nova lista.”
Podemos adicionar uma condição:
pares = [x for x in range(10) if x % 2 == 0]
Resultado:
[0, 2, 4, 6, 8]
Set comprehension
Também podemos criar conjuntos:
quadrados = {x ** 2 for x in range(5)}
Dict comprehension
E dicionários:
quadrados = { x: x ** 2 for x in range(5)}
O resultado será um dicionário contendo os números e seus respectivos quadrados.
Generator expression
Existe ainda a expressão geradora:
quadrados = (x ** 2 for x in range(5))
Ela se parece com uma compreensão de lista, mas utiliza parênteses.
Em vez de construir imediatamente uma lista completa, ela produz os valores conforme são solicitados.
Acesso a atributos, índices e fatias
Expressões também podem acessar partes de objetos.
Acesso a atributos
Usamos o ponto:
objeto.atributo
Por exemplo:
nome = "Python"nome.upper
Aqui estamos acessando o atributo upper.
Quando colocamos os parênteses:
nome.upper()
estamos realizando uma chamada.
Essa diferença é importante:
nome.upper
é acesso ao atributo.
nome.upper()
é uma chamada.
Índices
Podemos acessar elementos de uma coleção usando []:
frutas = ["maçã", "banana", "laranja"]frutas[0]
Resultado:
maçã
Também podemos utilizar índices negativos:
frutas[-1]
Resultado:
laranja
A subscrição de objetos está relacionada ao método especial __getitem__(). Para objetos que suportam esse protocolo, uma expressão como objeto[chave] utiliza esse mecanismo para obter o valor correspondente. Python documentation
Fatias
Também podemos selecionar uma parte da coleção:
frutas[0:2]
Resultado:
["maçã", "banana"]
Podemos usar:
frutas[:2]
ou:
frutas[1:]
O conceito é chamado de slicing, ou fatiamento.
Expressões com funções
Uma chamada de função também pode formar uma expressão:
len("Python")
O Python executa a função e obtém seu resultado.
Nesse caso:
len("Python")
resulta em:
6
Outro exemplo:
sum([10, 20, 30])
Resultado:
60
Argumentos posicionais
Podemos chamar:
pow(2, 3)
Os argumentos são fornecidos pela posição.
Argumentos nomeados
Também podemos utilizar argumentos nomeados:
print("Olá", end="!")
Aqui:
end="!"
é um argumento nomeado.
*args e **kwargs
Em funções, também podemos trabalhar com argumentos variáveis:
def somar(*args): return sum(args)
Agora:
somar(10, 20, 30)
produz:
60
Já **kwargs permite receber argumentos nomeados:
def mostrar(**kwargs): print(kwargs)
Uma chamada como:
mostrar(nome="Tiago", idade=25)
recebe esses valores como um dicionário.
Para ver funções, listas e chamadas de funções aplicadas em um exemplo mais próximo de um programa real, consulte também Criando um sistema de menus em Python com funções e listas.
return e None
Uma função pode retornar um valor:
def dobro(numero): return numero * 2
Podemos então escrever:
resultado = dobro(5)
A expressão:
dobro(5)
produz o valor:
10
Se uma função não tiver um return explícito:
def mensagem(): print("Olá")
o resultado retornado pela chamada é None.
Isso explica por que podemos encontrar:
resultado = mensagem()
mesmo que a função não tenha retornado explicitamente um valor.
__call__() e objetos que podem ser chamados
Em Python, funções são objetos chamáveis.
Algumas classes também podem criar objetos que podem ser chamados usando parênteses, por meio de __call__().
Por exemplo:
class Dobro: def __call__(self, numero): return numero * 2dobro = Dobro()print(dobro(5))
Resultado:
10
A aparência:
dobro(5)
é semelhante à chamada de uma função, embora dobro seja um objeto.
Esse é um exemplo de como a sintaxe de expressões Python pode ser conectada ao modelo de objetos da linguagem.
Geradores e yield
Agora chegamos a um conceito um pouco mais avançado.
Uma função que utiliza yield é uma função geradora. Quando chamada, ela produz um objeto iterador, e a execução da função avança conforme os valores são solicitados. Python documentation
Veja:
def numeros(): yield 1 yield 2 yield 3
Podemos utilizar:
for numero in numeros(): print(numero)
Resultado:
1
2
3
A diferença para um return é importante.
Com:
return 1
a função retorna e termina.
Com:
yield 1
a função fornece um valor e pode continuar posteriormente.
yield from
Também existe:
yield from
Por exemplo:
def numeros(): yield from [1, 2, 3]
Isso permite delegar a produção dos valores para outro iterável.
__next__()
Os geradores estão relacionados ao protocolo de iteração.
Podemos obter o próximo valor com next():
def numeros(): yield 1 yield 2gerador = numeros()print(next(gerador))print(next(gerador))
Resultado:
1
2
Internamente, o iterador fornece seu próximo valor por meio do protocolo associado a __next__().
Expressões assíncronas e await
O await aparece na programação assíncrona.
Por exemplo:
async def buscar_dados(): resultado = await alguma_operacao() return resultado
Nesse caso:
await alguma_operacao()
é uma expressão await.
Ela permite aguardar um objeto aguardável (awaitable) dentro de uma função assíncrona.
Funções declaradas com:
async def
são funções de corrotina. Elas podem conter expressões await. Python documentation
Um exemplo conceitual:
async def processar(): resultado = await buscar_dados() return resultado
O await não significa simplesmente “pare o programa”.
Ele faz parte do modelo de programação assíncrona do Python, permitindo que a execução aguarde uma operação assíncrona sem transformar todo o código em uma sequência tradicional de bloqueios.
Para um iniciante, o mais importante neste momento é reconhecer a estrutura:
await alguma_coisa()
e entender que ela pertence ao universo das expressões Python.
Métodos especiais relacionados aos operadores
Uma das características interessantes de Python é que determinados operadores estão relacionados a métodos especiais.
Por exemplo:
10 + 5
está relacionado ao mecanismo de __add__().
A documentação do modelo de dados descreve métodos especiais como __add__(), __sub__(), __mul__() e __matmul__() para implementar operações numéricas. Python documentation
Algumas relações importantes são:
| Operador | Método especial |
|---|---|
+ |
__add__() |
- |
__sub__() |
* |
__mul__() |
/ |
__truediv__() |
// |
__floordiv__() |
% |
__mod__() |
** |
__pow__() |
@ |
__matmul__() |
& |
__and__() |
^ |
__xor__() |
| |
__or__() |
<< |
__lshift__() |
>> |
__rshift__() |
-x |
__neg__() |
+x |
__pos__() |
~x |
__invert__() |
Isso permite que classes definam como determinados operadores devem funcionar para seus objetos.
Por exemplo, uma classe pode implementar __add__() para definir o comportamento de:
objeto1 + objeto2
Esse mecanismo é uma das razões pelas quais o mesmo operador pode funcionar com diferentes tipos de objetos.
Por que [] também está relacionado a métodos especiais?
Quando escrevemos:
lista[0]
Python precisa descobrir como obter o item correspondente.
Esse comportamento está relacionado a:
__getitem__()
Por isso, uma classe pode implementar esse método para permitir operações de subscrição:
objeto[0]
A documentação do Python também define __setitem__() para atribuições como objeto[chave] = valor e __delitem__() para exclusões. Python documentation
Existe ainda __class_getitem__(), que pode entrar em cena quando fazemos subscrição de uma classe, algo que aparece em construções relacionadas a tipos genéricos. Python documentation
Para iniciantes, a ideia principal é:
A sintaxe amigável que usamos no código pode estar conectada a métodos especiais definidos pelo próprio objeto.
Como reconhecer uma expressão em Python?
Uma maneira simples de começar é perguntar:
“Esta parte do código pode ser avaliada para produzir um valor?”
Veja:
10 + 20
Sim. Resultado:
30
idade > 18
Sim. Resultado:
True
nome.upper()
Sim. Resultado: uma nova string.
numeros[0]
Sim. Resultado: o elemento correspondente.
[x * 2 for x in numeros]
Sim. Resultado: uma nova lista.
Essa forma de pensar ajuda bastante na leitura de código.
Expressão não é a mesma coisa que instrução
Essa é uma distinção importante.
Considere:
10 + 5
Temos uma expressão.
Agora:
idade = 20
temos uma atribuição.
Mas existe uma relação interessante: expressões podem aparecer dentro de instruções.
Por exemplo:
idade = 10 + 5
A instrução de atribuição utiliza a expressão:
10 + 5
O resultado é então associado ao nome idade.
Outro exemplo:
if idade >= 18: print("Maior de idade")
A expressão:
idade >= 18
é utilizada para determinar o caminho que o programa seguirá.
Erros comuns ao trabalhar com expressões
Confundir = com ==
Errado:
if idade = 18:
Correto:
if idade == 18:
= é usado em atribuições.
== é usado para comparação de igualdade.
Confundir is com ==
Não use:
a is 10
como substituto geral para:
a == 10
== compara valores.
is verifica identidade.
Esquecer os parênteses de uma chamada
Veja:
nome.upper
e:
nome.upper()
O primeiro acessa o atributo.
O segundo realiza a chamada.
Tentar acessar um índice inexistente
Por exemplo:
numeros = [10, 20, 30]print(numeros[10])
Isso provoca um erro porque não existe uma posição 10 nessa lista.
Exemplos práticos
Vamos juntar alguns conceitos.
nome = "Tiago"idade = 25mensagem = f"{nome} tem {idade} anos."print(mensagem)
Aqui encontramos diferentes elementos que participam do processamento do programa.
Outro exemplo:
numeros = [1, 2, 3, 4, 5]pares = [numero for numero in numeros if numero % 2 == 0]print(pares)
A expressão:
numero % 2 == 0
combina:
- uma variável;
- o operador
%; - um literal;
- o operador
==; - outro literal.
E produz True ou False.
A compreensão utiliza esse resultado para decidir quais valores entram na nova lista.
Conclusão
Expressões estão presentes praticamente em todo código Python.
Elas podem ser extremamente simples:
10
ou combinar diversos elementos:
[x ** 2 for x in range(10) if x % 2 == 0]
Ao estudar expressões, você começa a enxergar o código Python de uma maneira diferente.
Você passa a identificar:
- literais, como
10e"Python"; - identificadores, como
idadeenome; - operadores, como
+,-,==ein; - coleções, como listas e dicionários;
- chamadas de funções;
- acesso a atributos e índices;
- compreensões;
- geradores;
yield;await.
O mais importante é não tentar decorar tudo de uma vez.
Comece reconhecendo expressões simples:
10 + 5
Depois avance para:
idade >= 18
e:
nome.upper()
Depois:
numeros[0]
E, quando esses conceitos estiverem confortáveis, avance para compreensões, geradores e programação assíncrona.
Esse caminho torna muito mais fácil compreender programas Python maiores.
