curso
Operador da morsa do Python: A expressão de atribuição (Tutorial)
O Python 3.8 introduziu um novo operador operador na linguagem. Seu nome oficial é aexpressão de atribuição e ela usa o operador :=
.
No entanto, é mais comumente chamado de operador de morsa pois ele se parece com as tarefas de uma morsa!
Houve controvérsia no mundo normalmente calmo do Python quando esse operador foi adicionado à linguagem, e seu uso ainda é relativamente limitado. Ainda assim, a expressão de atribuição agora faz parte do Python e pode ser útil em algumas situações.
Neste tutorial, você verá como funciona o operador walrus do Python e discutirá situações em que ele pode ser usado.
O que é o operador da morsa do Python?
A expressão de atribuição expressão de atribuiçãoque usa o operador :=
, é semelhante à expressão de atribuição mais comum que você usa. declaração de atribuiçãoque usa o operador =
. No entanto, há uma distinção importante entre os dois.
A declaração é uma unidade de código que executa alguma ação. Uma expressão é uma declaração que pode ser avaliada em um valor. Portanto, uma expressão retorna um valor, enquanto as declarações que não são expressões não retornam nenhum valor.
O REPL (Read, Evaluate, Print, and Loop) do Python exibe o valor de uma expressão assim que ela é avaliada. No entanto, nenhum valor é mostrado quando você executa uma instrução que não é uma expressão:
>>> import random # Not an expression
>>> 10 * 2 # An expression
20
A instrução import
não avalia nenhum valor. Entretanto, 10 * 2
é uma expressão que é avaliada como um valor.
A instrução de atribuição, que usa o operador =
, atribui um objeto a uma variável ou a outra referência, mas não retorna o valor. A expressão de atribuição, ou operador de morsa, executa a mesma ação que a instrução de atribuição, mas também retorna o objeto:
>>> value = 10 # Assignment statement
>>> value
10
>>> (value := 20) # Assignment expression
20
Observe que a instrução de atribuição não retorna o valor, ao contrário da expressão de atribuição. Portanto, uma expressão de atribuição combina várias operações:
- Ele avalia a expressão no lado direito do operador
:=
. - Ele atribui esse valor a um nome de variável.
- Ele retorna o valor.
Os parênteses são uma sintaxe obrigatória quando você usa a expressão de atribuição em vez de uma instrução de atribuição, como neste exemplo, para reduzir a ambiguidade. Você saberá mais sobre os requisitos de sintaxe do operador walrus mais adiante neste tutorial.
Uma expressão de atribuição pode ser usada em qualquer lugar onde expressões possam ser usadas no Python. Vejamos um exemplo:
print(f"The number is {(value := 50)}")
print(value)
The number is 50
50
O nome da variável value
é definido em f-string na primeira linha. No entanto, o número inteiro também é retornado diretamente para as chaves na string f. As chaves em f-strings devem incluir uma expressão, o que explica por que uma instrução de atribuição não pode ser usada.
Casos de uso do operador Walrus do Python
Dois casos de uso comuns para o operador de morsa são a simplificação e a otimização do código.
Simplificando o código
Um caso de uso comum do operador walrus é simplificar o código em que uma variável normalmente precisaria ser definida antes de ser usada, como em algumas instruções condicionais. Considere o seguinte loop while
:
import random
value = random.randint(1, 20)
while value < 18:
print(value)
value = random.randint(1, 20)
7
5
1
11
12
1
9
Esse código executa o bloco while
desde que o valor aleatório gerado seja menor que 18
. A variável value
precisa ser definida antes do loop while
para que possa ser usada na instrução while
. Um novo número aleatório é atribuído a value
no final do bloco while
.
A expressão de atribuição :=
pode ser usada para reduzir as linhas de código e para chamar a função random.randint()
em um único local do programa:
import random
while (value := random.randint(1, 20)) < 18:
print(value)
1
9
2
4
9
15
11
Um novo número aleatório é gerado e atribuído a value
sempre que o loop while
inicia uma nova iteração.
Otimização de código
Vamos dar uma olhada em outro exemplo usando compreensões de lista. Considere o código a seguir, que filtra uma lista de strings contendo datas e cria uma lista de objetos datetime.datetime
objetos contendo apenas datas em um determinado ano:
from datetime import datetime
def format_date(date_str):
return datetime.strptime(date_str, "%Y-%m-%d")
dates = ["2024-01-01", "2022-12-31", "2024-06-15", "2023-08-23", "2024-11-30"]
formatted_dates = [
format_date(date)
for date in dates
if format_date(date).year == 2024
]
print(formatted_dates)
[datetime.datetime(2024, 1, 1, 0, 0), datetime.datetime(2024, 6, 15, 0, 0), datetime.datetime(2024, 11, 30, 0, 0)]
A função format_date()
aceita uma cadeia de caracteres com uma data no formatoaaaa-mm-dd e retorna um objeto datetime.datetime
. Um dos atributos do objeto datetime.datetime
é .year
, que contém o componente de ano da data.
Somente as três datas de 2024 estão incluídas na lista final, que também contém objetos datetime.datetime
em vez de cadeias de caracteres. A compreensão da lista inclui uma cláusula if
, que chama format_date()
. Entretanto, format_date()
também é chamado na primeira expressão da compreensão de lista, que gera os valores a serem adicionados à lista. Chamar a função com o mesmo argumento duas vezes é ineficiente, especialmente se a função for um gargalo no desempenho do programa.
Uma opção para evitar chamar a mesma função duas vezes é chamar a função e atribuí-la a uma variável antes de usá-la. No entanto, isso não pode ser feito com uma instrução de atribuição enquanto você ainda estiver usando uma compreensão de lista. Essa solução requer um loop for
padrão:
from datetime import datetime
def format_date(date_str):
return datetime.strptime(date_str, "%Y-%m-%d")
dates = ["2024-01-01", "2022-12-31", "2024-06-15", "2023-08-23", "2024-11-30"]
formatted_dates = []
for date in dates:
formatted_date = format_date(date)
if formatted_date.year == 2024:
formatted_dates.append(formatted_date)
print(formatted_dates)
[datetime.datetime(2024, 1, 1, 0, 0), datetime.datetime(2024, 6, 15, 0, 0), datetime.datetime(2024, 11, 30, 0, 0)]
O operador de morsa oferece uma alternativa compatível com uma compreensão de lista, pois a data formatada retornada pela função pode ser atribuída a um nome de variável e retornada na mesma expressão:
from datetime import datetime
def format_date(date_str):
return datetime.strptime(date_str, "%Y-%m-%d")
dates = ["2024-01-01", "2022-12-31", "2024-06-15", "2023-08-23", "2024-11-30"]
formatted_dates = [
formatted_date
for date in dates
if (formatted_date := format_date(date)).year == 2024
]
print(formatted_dates)
[datetime.datetime(2024, 1, 1, 0, 0), datetime.datetime(2024, 6, 15, 0, 0), datetime.datetime(2024, 11, 30, 0, 0)]
A expressão de atribuição na compreensão de lista é a expressão entre parênteses, (formatted_date := format_date(date))
. Essa expressão chama a função format_date()
, atribui seu valor à variável formatted_date
e retorna o valor. Como a expressão de atribuição é avaliada como um objeto datetime.datetime
, o código acessa o atributo .year
, que é comparado a 2024
usando o operador de igualdade.
A cláusula if
na compreensão de lista é executada antes da expressão que gera o valor a ser armazenado na lista. Portanto, o operador de morsa é usado na cláusula if
, e a variável definida nessa expressão de atribuição é usada como a primeira expressão na compreensão de lista.
Polêmica sobre o operador de morsa do Python
A expressão de atribuição não é apreciada por todos os programadores Python. Alguns veem isso como uma forma de simplificar o código, mas outros acham que isso torna o código menos legível e preferem as opções mais longas. A legibilidade pode ser subjetiva, portanto, as opiniões variam quanto ao fato de o operador de morsa tornar o código mais ou menos legível.
O último exemplo da seção anterior mostra as compensações necessárias. Sem o operador de morsa, o código neste exemplo precisa que uma lista vazia seja inicializada primeiro e, em seguida, os valores são anexados a ela em um loop for
. Essa solução é mais longa e menos eficiente do que usar compreensões de lista, que são otimizadas para esse trabalho.
No entanto, a solução padrão do loop for
pode ser mais legível para alguns programadores que preferem escrever mais código em vez de usar o operador de morsa, especialmente se o desempenho não for uma preocupação.
Muitos guias de estilo de codificação ainda recomendam que você evite a expressão de atribuição ou que a use com moderação.
Operador da morsa do Python: Regras de sintaxe
É comum que você encontre erros de sintaxe ao explorar inicialmente o operador de morsa devido às suas regras de sintaxe.
Para evitar confusão entre a instrução de atribuição =
e a expressão de atribuição :=
, não há nenhuma situação em que ambas as opções sejam sintaticamente válidas. Por esse motivo, muitas vezes é necessário colocar a expressão de atribuição entre parênteses:
(value := 20) # Valid
value := 20 # Invalid (SyntaxError)
O requisito de incluir a expressão de atribuição entre parênteses nessa situação é o oposto do requisito da instrução de atribuição, que não pode ser incluída entre parênteses.
No entanto, a expressão de atribuição nem sempre precisa de parênteses:
import random
if value := random.randint(0, 3):
print(f"{value} is greater than 0")
1 is greater than 0
A expressão de atribuição na instrução if
gera um número aleatório entre 0 e 3 e o atribui à variável value
. Os números inteiros 1
, 2
e 3
são verdadeirose o código no bloco if
será executado quando esses valores forem gerados. No entanto, quando random.randint()
retorna 0
, que é falso, o bloco if
não é executado.
A instrução de atribuição não é válida após uma palavra-chave if
. Portanto, não há confusão nessa situação, e os parênteses não são necessários.
Esse exemplo também demonstra outro ponto importante sobre a expressão de atribuição. O escopo da variável atribuída segue as regras normais do regras do LEGB. Portanto, a variável value
está disponível em todos os lugares do escopo global neste exemplo:
import random
if value := random.randint(0, 3):
print(f"{value} is greater than 0")
print(value)
2 is greater than 0
2
Se uma expressão de atribuição for usada em uma definição de função, a variável só estará disponível localmente na função. Esse é o mesmo comportamento das variáveis criadas usando uma instrução de atribuição.
Esse exemplo pode ser modificado para mostrar outra possível armadilha ao usar o operador de morsa. Vamos alterar esse código para incluir um operador de comparação na instrução if
:
import random
if value := random.randint(0, 3) < 2:
print(f"{value} is less than 2")
True is less than 2
A saída mostrada indica o problema com esse código, pois value
é o booleano True
em vez de um número inteiro. O operador da morsa tem a menor precedência de todos os operadorese somente a vírgula tem precedência mais baixa. Portanto, o operador menor que <
é avaliado primeiro, e seu resultado é atribuído a value
. Os parênteses são necessários para lidar com essa situação:
import random
if (value := random.randint(0, 3)) < 2:
print(f"{value} is less than 2")
0 is less than 2
A expressão de atribuição agora é avaliada primeiro, pois os parênteses têm a precedência mais alta. O número retornado por random.randint()
é atribuído a value
e é usado como o primeiro operando do operador less than.
Diferentemente da instrução de atribuição, o operador de morsa só pode atribuir valores a nomes de variáveis e não pode ser usado para atribuir valores a subscritos ou atributos:
(name := "James") # Valid
points = {"James": 10, "Mary": 20}
(points["Sarah"] := 30) # Invalid
class Article:
pass
article = Article()
(article.title := "The Walrus Operator") # Invalid
Não é possível atribuir um valor usando um subscrito ou a um atributo usando o operador de morsa.
Conclusão
A expressão de atribuição, que usa a sintaxe :=
e é frequentemente chamada de operador de morsa, é uma adição relativamente nova ao Python. A instrução de atribuição, que usa o operador =
, é a forma mais comum de atribuir um valor a um nome de variável.
No entanto, o operador de morsa amplia essa operação de atribuição retornando também o valor atribuído, o que torna essa atribuição uma expressão. Portanto, você pode usar a expressão de atribuição onde quer que possa usar outras expressões em Python.
No entanto, a comunidade Python está dividida quanto à utilidade e legibilidade do operador walrus. Por esse motivo, a expressão de atribuição não é usada com tanta frequência quanto outras novas adições ao Python. É ótimo que você saiba como usar esse operador, mas não o use em excesso!
Aprenda Python com estes cursos!
curso
Intermediate Python for Developers
curso
Introduction to Statistics in Python
tutorial
Operadores em Python
tutorial
Escopo das variáveis em Python
tutorial
Declaração de caso de troca do Python: Um guia para iniciantes
tutorial
Programação orientada a objetos em Python (OOP): Tutorial
tutorial
Tutorial de Python
DataCamp Team
3 min
tutorial