Curso
A maioria de nós usa asteriscos como operadores de multiplicação e potência, mas eles também têm uma ampla gama de usos como operador de prefixo em Python. Depois de ler este artigo, você vai conhecer todas as formas de usar asteriscos.
Os asteriscos têm muitos casos de uso específicos em Python. Em geral, estamos familiarizados com os operadores de multiplicação e potência. Eles também permitem outras operações como unpacking, passagem de argumentos etc., em diferentes situações. Primeiro, vamos ver o uso geral dos asteriscos.
Uso geral de * e **
* é usado como operador de multiplicação, enquanto ** é usado como operador de potência.
## declaring variables
a, b = 2,3
## multiplication
print("Multiplication of 2 and 3 is {}".format(a * b))
## as power operator
print("2 power 3 is {}".format(a ** b))
Multiplication of 2 and 3 is 6
2 power 3 is 8
Agora você viu o uso geral e mais comum de asteriscos. Existem, porém, casos de uso de asteriscos que talvez você não conheça. Vamos explorar os usos menos óbvios dos asteriscos.
1. Unpacking usando *
Fazer o unpacking dos elementos de uma list/tuple/set usando *. Vamos usar unpacking em códigos futuros para implementar outros recursos dos asteriscos. Unpacking é a ideia básica por trás do uso de asteriscos como operadores de prefixo.
Vamos supor que queremos atribuir o primeiro elemento da list/tuple/set a a e os elementos restantes a b. Em geral, faríamos isso usando slicing.
## general approach
nums = [i for i in range(1, 6)]
a = nums[0]
b = nums[1:]
print(a, b)
print("--------------------------")
## hard approach
squares = [i ** 2 for i in range(1, 6)]
a = squares[0]
b = []
for i in range(1, len(squares)):
b.append(squares[i])
print(a, b)
1 [2, 3, 4, 5]
--------------------------
1 [4, 9, 16, 25]
Agora, vamos usar o operador * para fazer isso em uma única linha de código.
nums = [i for i in range(1, 6)]
## a will be 1 and b will be a list containing remaining elements
a, *b = nums
print(a, b)
1 [2, 3, 4, 5]
Aqui, a é uma variável simples que recebe um valor da lista e b é uma lista. O unpacking funciona em tuples e sets da mesma forma que funciona com lists. Vamos ver alguns exemplos.
## using tuple
## here first element will assign to a and last element to c
a, *b, c = (1, 2, 3, 4, 5)
print(a, b, c)
print("--------------------------")
## using sets
a, *b, c = {1, 4, 9, 16, 25}
print(a, b, c)
1 [2, 3, 4] 5
--------------------------
1 [4, 9, 16] 25
1.1. Combinando iteráveis diferentes
Podemos adicionar dois iteráveis diferentes em list/sets/tuples usando unpacking. Normalmente, precisaríamos converter os iteráveis e combiná-los em um só. Isso não é necessário se usarmos *. Veja um exemplo.
## combining a tuple, list, set
nums = [1, 2, 3]
nums2 = (4, 5, 6)
nums3 = {7, 8, 9}
## we convert the combined elements into any iterable we want
## here i am converting into a list
_list = [*nums, *nums2, *nums3]
_tuple = (*nums, *nums2, *nums3)
_set = {*nums, *nums2, *nums3}
print(type(_list))
print(_list)
print("------------------------")
print(type(_tuple))
print(_tuple)
print("------------------------")
print(type(_set))
print(_set)
<class 'list'>
[1, 2, 3, 4, 5, 6, 8, 9, 7]
------------------------
<class 'tuple'>
(1, 2, 3, 4, 5, 6, 8, 9, 7)
------------------------
<class 'set'>
{1, 2, 3, 4, 5, 6, 7, 8, 9}
1.2. Unpacking aninhado
Unpacking aninhado é extrair elementos do primeiro nível dos itens já extraídos. Veja o exemplo para entender do que estou falando.
languages = ["Python", "HTML", "CSS", "JS"]
## unpacking
[[first_letter, *remaining], *other] = languages
print(first_letter, remaining, other)
P ['y', 't', 'h', 'o', 'n'] ['HTML', 'CSS', 'JS']
2. Unpacking usando **
Como vimos antes, ** é usado para fazer o unpacking dos elementos de um dictionary. Precisamos conhecer as chaves do dicionário para extrair os valores durante o unpacking. Veja um exemplo.
## sample dictionary
person = {"name":"John", "age":19, "year_of_passing":"2021"}
string = "Name:-{name} Year Of Graduation:-{year_of_passing} Age:-{age}".format(**person)
print(string)
Name:-John Year Of Graduation:-2021 Age:-19
Não é tão comum usar ** para extrair elementos de um dictionary.
3. Asteriscos em funções
Podemos passar e capturar argumentos usando asteriscos em funções para reduzir linhas de código.
3.1. Unpacking em funções
O operador * é usado para chamar uma função fazendo o unpacking de um iterável. Suponha que temos uma list e precisamos passar todos os seus elementos para o print() separadamente. O que você faria? Talvez esteja pensando em um loop. Mas o * facilita muito isso.
Basta passar o iterável como *nome_do_iterável. Ele faz o unpacking e passa todos os elementos separadamente.
nums = [i for i in range(1, 6)]
## passsing list using the *
print(*nums)
1 2 3 4 5
nums = (i for i in range(1, 6))
## passsing tuple using the *
print(*nums, sep = ", ")
1, 2, 3, 4, 5
3.2. Agrupando elementos (packing)
Packing significa capturar múltiplos elementos de uma vez. Usamos esse recurso em chamadas de função.
def average(*nums):
return sum(nums) / len(nums)
Agora podemos passar qualquer quantidade de inteiros para calcular a média. A função average captura todos os argumentos como uma lista.
## calling the average with some numbers
print(average(1, 2, 3, 4, 5))
3.0
Vimos como capturar múltiplos elementos em uma lista usando *. Agora, vamos aprender a capturar vários pares chave-valor usando **.
def _object(name, **properties):
print(name, properties)
_object("Car", color="Red", cost=999999, company="Ferrari")
Car {'ceo': 'Louis', 'color': 'Red', 'cost': 999999, 'company': 'Ferrari'}
4. Argumentos somente por palavra-chave com argumentos posicionais
Argumentos com nome são chamados de keyword arguments (argumentos por palavra‑chave). Os outros são argumentos posicionais. Primeiro, entenda a diferença entre argumentos por palavra‑chave e posicionais. Veja um exemplo.
## name is a positional argument
## color and cost are keyword arguments
def sample(car, color = None, cost = None):
print("Car:-{} Color:-{}, Cost:-{}".format(car, color, cost))
Podemos usar o nome do parâmetro para passar argumentos ao chamar uma função com argumentos por palavra‑chave. Se não passarmos nada para os argumentos por palavra‑chave, eles assumem o valor padrão definido na função.
Podemos especificar argumentos por palavra‑chave usando as palavras‑chave ou a posição dos argumentos.
sample("Ferrari", "Red", 999999)
Car:-Ferrari Color:-Red, Cost:-999999
sample("Ferrari", cost = 999999, color = "Red")
Car:-Ferrari Color:-Red, Cost:-999999
A ordem dos argumentos por palavra‑chave não é essencial se usarmos os nomes definidos na função.
sample("Ferrari", color = "Green")
Car:-Ferrari Color:-Green, Cost:-None
Agora você já entende posicionais e por palavra‑chave. Vamos ao ponto principal.
Argumentos keyword-only só podem ser especificados pelas palavras‑chave. Não dá para passá‑los por posição como vimos antes. Precisamos declarar os argumentos por palavra‑chave depois dos argumentos * para capturar os keyword-only.
def keyword_only(*items, _list, default = False):
print(items)
print(_list)
print(default)
Precisamos usar as palavras‑chave _list e default ao chamar a função, porque elas vêm depois de *items. Se não usarmos as palavras‑chave, teremos um erro. Veja os dois casos.
nums = [i ** 2 for i in range(1, 6)]
## calling the function
keyword_only(1, 2, 3, 4, 5, _list = nums, default = True)
(1, 2, 3, 4, 5)
[1, 4, 9, 16, 25]
True
E se chamarmos a função keyword_only usando argumentos posicionais?
nums = [i ** 2 for i in range(1, 6)]
## calling the function will raise an error
keyword_only(1, 2, 3, 4, 5, nums, False)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-85-bf737d8a8bfc> in <module>()
1 nums = [i ** 2 for i in range(1, 6)]
----> 2 keyword_only(1, 2, 3, 4, 5, nums, False)
TypeError: keyword_only() missing 1 required keyword-only argument: '_list'
Recebemos um erro informando que falta um argumento obrigatório do tipo keyword-only. Portanto, precisamos usar palavras‑chave ao chamar argumentos keyword-only. Argumentos keyword-only são definidos apenas depois dos argumentos * nas funções.
5. Argumentos keyword-only sem argumentos posicionais
Se quisermos aceitar apenas argumentos keyword-only sem nenhum argumento posicional, o Python permite usar * nos parâmetros da função para isso. Veja um exemplo.
def _sample(*, name):
print(name)
A função acima aceita apenas argumentos keyword-only. Precisamos passar o argumento com a palavra‑chave. Caso contrário, teremos um erro. O * na definição da função garante que ela só aceite argumentos usando palavras‑chave. Qualquer parâmetro definido após * na função deve ser especificado com palavras‑chave na chamada.
## calling the function using keyword 'name'
_sample(name = "Datacamp")
Datacamp
## calling the function without using keyword 'name'
## we will get a TypeError
_sample("Datacamp")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-12-fe0d3718b56c> in <module>()
1 ## calling the function without using keyword 'name'
2 ## we will get a TypeError
----> 3 samp("Datacamp")
TypeError: samp() takes 0 positional arguments but 1 was given
Fica claro que a função _sample() só aceita argumentos keyword-only*.
Conclusão
Novos recursos são adicionados a cada nova versão do Python. Os asteriscos são especiais e ajudam a reduzir partes do código. Não dá para aceitar múltiplos argumentos posicionais sem *, e argumentos keyword-only também precisam de * para implementar esse recurso. Outras operações com asteriscos até poderiam ser feitas com várias linhas de código. Pratique para entender tudo direitinho. Obrigado por ler!
Se quiser aprender mais sobre Python, faça o curso Python Data Science Toolbox (Part 1) da DataCamp.
Bons códigos :)
