Python3 10 – Zip, Map, Reduce, Filter e Lambda
- Python3 01 – Iniciando…
- Python3 02 – “Variáveis”
- Python3 03 – Controle de Fluxo e Funções
- Python3 04 – Sequências: Strings e Tuplas
- Python3 05 – Sequências: Listas
- Python3 06 – Conjuntos (Set)
- Python3 07 – Dicionários
- Python3 08 – Tratamento de Exceções e Arquivos
- Python3 09 – Classes e Orientação a Objetos
- Python3 10 – Zip, Map, Reduce, Filter e Lambda
Índice
Ao longo destes textos, algumas das classes builtin do Python1 foram tratadas como funções, apenas pela comodidade de não ter de adentrar em explicações prematuras sobre classes e orientação a objetos. Comandos como list()
, tuple()
, dict()
, complex()
, float()
, int()
, str()
, entre outros empregados ao longo destes textos, são todos classes no Python, os quais retornam como objetos uma lista, tupla, dicionário, número complexo, ponto flutuante, inteiro e string, respectivamente.
Neste texto, será tratado de mais algumas classes especiais do Python, como a zip, map e filter, além do comando para criação de funções anônimas, lambda e da função reduce
. Estas são ferramentas internas do Python intimamente ligadas a programação funcional.
No Python 3, as classes zip, map e filter geram iteráveis do tipo zip, map e filter, respectivamente, enquanto que no Python 2 estas classes geravam uma lista com os elementos. Por este motivo, estas classes serão associados às classes list
, tuple
e dict
para gerarem objetos visíveis, como lista, tupla e dicionário. Esta escolha no Python 3 se deve à vasta utilização destas classes apenas para serem empregadas como iteradores, ou mesmo em laços de repetição.
1. Classe zip
A classe zip()
retorna um objeto do tipo zip, um iterável que associa os elementos dos iteráveis passados como argumentos. Sua sintaxe é apresentada a seguir:
zip(iter1[, iter2[, iter3[...]]])
O comando zip
criará um iterador do tipo zip com os elementos tomados de cada iterador passado como argumento. Supondo que se tenha dado o comando zip(iter1, iter2, iter3, ...)
, sua saída será um iterador semelhante a uma lista de tuplas com os conteúdos: (i11, i21, i31, …), (i21, i22, i23, …), (i31, i32, i33, …), …, onde i11 corresponde ao elemento 1 do iterador 1, o i21 o elementos 1 do iterador 2 e assim por diante.
Os comandos a seguir ilustram a aplicação da classe zip()
:
[xterm color=’true’ py=’true’]
>>> L = (1,2,3,4)
>>> zip(L)
<zip object at 0x7ff2f5938288>
>>> list(zip(L))
[(1,), (2,), (3,), (4,)]
>>>
>>> from string import ascii_lowercase, ascii_uppercase
>>> ascii_lowercase, ascii_uppercase
(‘abcdefghijklmnopqrstuvwxyz’, ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’)
>>>
>>> List = list(zip(L, ascii_lowercase, ascii_uppercase))
>>> Dic = dict(zip(L, ascii_lowercase))
>>> List
[(1, ‘a’, ‘A’), (2, ‘b’, ‘B’), (3, ‘c’, ‘C’), (4, ‘d’, ‘D’)]
>>> Dic
{1: ‘a’, 2: ‘b’, 3: ‘c’, 4: ‘d’}
[/xterm]
No primeiro comando, é criado um objeto zip com os elementos da lista L
e elementos vazios no endereço de memória 0x7ff2f604e488. Sendo um iterável, este objeto pode ser usado para gerar uma lista, tupla, dicionário ou ser empregado em um laço de repetição. A linha list(zip(L))
emprega a classe list para gerar uma lista de tuplas a partir do objeto zip, usando os elementos da lista L
e um elemento vazio.
No import seguinte, a biblioteca string é empregada para importar os caracteres ascii minúsculos e maiúsculos (ascii_lowercase
, ascii_uppercase
). Em seguida, estas strings, também iteradores, são passadas a classe zip para gerar uma lista, List
, com as tuplas que associam os elementos da lista L
, com os elementos das strings ascii_lowercase
e ascii_uppercase
.
O dicionário Dic
é criado utilizando o iterador zip criado pela lista L e pela string ascii_lowercase
, mapeando os quatro primeiros elementos da string ascii_lowercase
com os índices da lista L
.
2. Classe map
A classe map
cria um objeto do tipo map
. Sua sintaxe é apresentada a seguir:
map(Função, Iterável)
O objeto gerado será a um iterável cujos elementos são os resultados da aplicação dos elementos do Iterável
na Função
passada como argumento. Veja os comandos a seguir:
[xterm color=’true’ py=’true’]
>>> def cubo(x):
… return x**3
…
>>> map(cubo, range(5))
<map object at 0x7f667c44e278>
>>> list(map(cubo, range(5)))
[0, 1, 8, 27, 64]
>>> list(map(cubo, range(10)))
[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
[/xterm]
3. Classe filter
A classe filter retorna um objeto iterador, cujos elementos passam por uma função filtro. Sua sintaxe é apresentada a seguir:
filter(Função, Iterável)
O objeto gerado é um iterador cujos elementos são os elementos do Iterável, filtrados pela Função passada como parâmetro. A Função em questão deve retornar True
ou False
para cada elemento do Iterável. Veja os exemplos a seguir:
[xterm color=’true’ py=’true’]
>>> def é_par(n):
… return True if n%2 == 0 else False
…
>>> list(filter(é_par, range(11)))
[0, 2, 4, 6, 8, 10]
>>>
>>> def é_primo(n):
… if n in (1, 2):
… return True
… for i in range(2, n):
… if n % i == 0:
… return False
… return True
…
>>> list(filter(é_primo, range(100, 200)))
[101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163,
167, 173, 179, 181, 191, 193, 197, 199]
[/xterm]
Primeiro é definida a função é_par(n)
para retornar True
se n
for um número par. Em seguida, esta função é passada para a classe filter, que gera um iterador com todos os pares entre 0 e 10, convertido em uma lista pela classe list.
Na sequência, é empregada a função é_primo()
para gerar a lista de números primos entre 100 e 200.
4. Função reduce
Por um dessabor do Guido van Rossum, criador da linguagem Python, a função reduce()
foi removida do builtins do Python 3 e transferida a uma biblioteca functools. O texto de 10 de março de 2005 ilustra o ocorrido:
Admito estar de acordo com Guido van Rossum. Primeiro a sua sintaxe:
reduce(Func, Iterável)
Neste caso, a Func deve ser uma função de dois parâmetros que gera um único resultado. A função reduce()
irá pegar os dois primeiros elementos do Iterável, e1
e e2
, e passá-los à função Func, Func(e1, e2)
. O resultado será passado à função Func novamente, juntamente com o próximo elemento do Iterável, e3
, Func(Func(e1, e2), e3)
. O processo se repete ao próximo elemento do Iterável, Func(Func(Func(e1, e2), e3), e4)
, e assim por diante até que o último elemento seja consumido. Veja o exemplo a seguir:
[xterm color=’true’ py=’true’]
>>> def produto(x, y):
… return x*y
…
>>> reduce(produto, [1, 2, 3, 4, 5])
120
[/xterm]
O diagrama a seguir ilustra a evolução da função reduce()
sobre os elementos da lista passada.
Em suma, a função reduce()
aplicada à função produto()
e à lista de inteiros de 1 a 5 reproduziu o fatorial de 5.
O somatório também poderia ser implementado pela função reduce()
com as linhas abaixo:
[xterm color=’true’ py=’true’]
>>> def soma(x, y):
… return x+y
…
>>> reduce(soma, range(6))
15
[/xterm]
O resultado é a soma dos inteiros 0 + 1 + 2 + 3 + 4 + 5 = 15
. O código é apenas ilustrativo, existe a função sum()
para isto.
5. Função Anônima lambda
Assim como outras linguagens, o Python possui suporte a funções anônimas através do comando lambda
. Funções anônimas geralmente são funções curtas de uso localizado, podendo ser descartadas após seu uso. Diferentemente das funções definidas pelo comando def
, as quais necessitam ser atribuídas a um nome após a sua criação, ao criar uma função anônima, o Python apenas retorna uma função sem nome. As linhas abaixo ilustram isto:
[xterm color=’true’ py=’true’]
>>> soma.__name__
‘soma’
>>> produto.__name__
‘produto’
>>> SOMA = lambda x, y: x*y
>>> PRODUTO = lambda x, y: x*y
>>> SOMA.__name__
‘<lambda>’
>>> PRODUTO.__name__
‘<lambda>’
[/xterm]
As funções soma
e produto
, definidas anteriormente, possuem o atributo __name__
com o nome da função no caso soma e produto. Já as funções anônimas atribuídas aos apontadores SOMA
e PRODUTO
possuem no atributo __nome__
apenas uma referência a funções anônimas, '<lambda>'
.
Este conceito e o nome da função são ‘emprestados’ da linguagem Lisp
. Sua sintaxe é apresentada a seguir:
lambda Variáveis: Expressão
Onde Variáveis é uma lista de variáveis separadas por vírgula e Expressão é a expressão matemática ou lógica.
Para ilustrar algumas aplicações, veja como algumas das listas anteriores podem ser facilmente criadas com o auxílio do comando lambda
:
[xterm color=’true’ py=’true’]
>>> list(map(lambda x: x**3, range(5)))
[0, 1, 8, 27, 64]
>>>
>>> list(filter(lambda n: True if n%2 == 0 else False, range(11)))
[0, 2, 4, 6, 8, 10]
>>>
>>> reduce(lambda x, y: x*y, range(1, 6))
120
>>>
>>> reduce(lambda x, y: x+y, range(1, 6))
15
[/xterm]
6. Conclusões
Estas classes e funções dão novas dimensões à programação em Python, sendo sempre aconselhável dar uma boa olhada nelas antes de iniciar o desenvolvimento de algum código.
Para o próximo texto está sendo preparado um detalhamento mais profundo sobre iteradores e geradores, mas ainda percebo que deveria adicionar mais algum assunto.
Deixe uma resposta