Jose: Olá pessoal,
e neste vídeo estamos falando de geradores em Python.
Estou muito animado para
esta seção, porque vamos falar sobre algumas coisas
mais avançadas e geradores são um desses
tópicos em Python que muitos
cursos nem sequer mencionam, mas eles são essenciais para o
desempenho e também porque o e -Desenvolvimento -sync em
Python,
o desenvolvimento e-synchronous
que vamos aprender mais tarde é construído sobre esses geradores.
Quando você entende os
geradores, muitas coisas no Python começam a se tornar muito mais claras.
Então, o que é um gerador?
Um gerador em Python é uma função.
É uma função especial.
Veja uma função que lembra o estado em
que ela está entre
as execuções, portanto, você pode executar a
função várias vezes e ela se
lembrará da última vez que você a executou.
Então isso soa bem estranho, deixe-me explicar com um exemplo.
Imagine que você queria criar uma
lista de 100
números, muito simples, você deseja obter uma nova lista com números de
zero a 99, não incluindo 100.
Então você poderia fazer uma função como esta.
Obviamente, não usando intervalo e assim por diante, você sabe alcance.
Não vamos usar o intervalo, vamos construir uma lista do zero.
Como você faria.
Uma boa maneira de fazer isso seria começar com uma lista vazia.
Digamos que chame nums e faça com que seja igual a uma lista vazia.
E também comece com um índice igual a zero.
Então, enquanto eu for menor que
100, digamos que ponto nums aponte i.
Então você vai anexar zero no começo.
Então você vai incrementar i por um, que
vai se tornar um.
Você vai anexar um, repetir, acrescentar
dois, depois três e assim por diante, até chegar a 99.
E no final desta função
retornamos nums, que é a sua lista de números.
Se imprimirmos cem números e rodarmos isso.
Podemos ver que
contém aqui nossa lista de cem números.
Claro que poderíamos usar a compreensão da lista para isso.
Poderíamos usar a função
range, mas por enquanto vamos supor
que esta é uma maneira legal de fazer isso, porque
o que eu estou realmente explicando é essencialmente como a função range trabalha por dentro.
Então, construímos uma
lista, preenchemos os primeiros cem números e depois retornamos.
Agora temos cem números em uma lista.
Esta lista inteira está na memória do seu computador armazenada como
este valor de retorno da função.
Agora, cem números não são muito
grandes, é uma quantidade
pequena de espaço, mas digamos que queremos armazenar 10 milhões,
milhões são como uma centena de
números, mas seria algo como um milhão de números.
Você poderia gerar uma lista de um milhão
de números e armazená-lo
nesta variável que vai para a memória
do seu computador e é presumivelmente uma quantidade
maior de memória, porque cada um
desses números está ocupando uma pequena quantidade da memória do seu computador.
Se você queria 10 milhões de números, então é maior e assim.
Agora, ter 10 milhões de números não é um ótimo exemplo, mas
imagine que você tenha uma lista muito longa de algo.
Por exemplo, eles costumam ser
usados no cálculo de números primos e
em big data e,
por vezes, talvez você queira grandes listas de coisas.
Então, um gerador é usado para contornar esse problema porque
a suposição é que você não precisa de 100
números de uma só vez.
O que você precisa é de zero para que você possa fazer algo com isso.
E então um para que você possa fazer algo com isso.
E então dois para que você possa fazer algo com isso.
Por exemplo, com essa centena
de números, poderíamos então multiplicá-los por dois e armazená-los em outra lista.
Como você faria isso?
Você faria algo como menos compreensão,
x vezes dois para x em cem números.
O que você está fazendo aqui
é usar essa lista para isolar e multiplicar cada número por dois.
Vamos pensar que essa
multiplicação por dois é uma operação
que queremos fazer nesses números para calcular algo.
Outro exemplo seria, se você tem muitos
usuários e quer calcular o envolvimento em torno deles,
ou como eles estão envolvidos com
seu sistema, ou algo assim.
Essencialmente, você quer passar por cima
de cada elemento e realizar uma operação.
A coisa aqui é que você não precisa de todos os elementos de uma só vez.
Você precisa deles um por um.
Então é para isso que os geradores são usados.
Em vez de ter toda a lista de elementos,
o que você faz é que
o gerador lhe fornece o
primeiro elemento da lista, sem armazenar toda a lista na memória.
Da próxima vez que você
chamar o gerador, ele lembra o elemento que lhe
deu a última e sabe dar o segundo elemento.
Então você o executa novamente e lhe dá o terceiro elemento,
e assim por diante.
Nunca armazena a lista na memória,
ela sempre lembra apenas o último número que ela lhe
deu, então ela pode lhe dar a próxima.
Você tem que divertir a
função toda vez que você quer um novo número,
e é por isso que ele é chamado de
gerador, porque gera números, ou mesmo strings, ou usuários ou o que quer que você queira gerar.
Veja como você faria isso, em vez de "nums". acrescentar (i) ", você
diz" yield i ", pois i é o número
que queremos retornar, não precisamos
mais deste nums colchetes iguais, e
também não precisamos mais do segmento de retorno.
Então agora essa função aqui é chamada de função geradora.
O rendimento é muito parecido com o retorno, mas o que
acontece é que dá a você quando você o chama, e então
ele se lembra que está aqui, está parado logo antes
da linha cinco. Logo após a linha quatro
lá no meio.
Da próxima vez que você chamar a função, ela
continuará, então o que ela fará
é incrementar i por um, irá executar novamente o
loop e produzir um, dar-lhe um e depois parar.
Da próxima vez que você
ligar, ele continuará aumentando, eu compro
um e repito o loop e, em seguida, dou dois, e então ele para, e assim por diante.
Eventualmente, quando você ficar
sem números, ele não renderá nenhum.
E então você sabe que está acabado.
Então, como vamos fazer isso?
Vamos, em primeiro lugar, imprimir cem números.
Observe como não nos dá mais uma
lista, agora nos dá um objeto gerador, que
é chamado de cem números, daí o
nome da nossa função.
Também nos fornece o endereço de memória do nosso objeto.
Observe como definimos uma função, mas a
impressão está nos dizendo que isso é um objeto,
porque o Python no
segundo plano percebe que você usou yield,
você está criando um gerador e os transforma em um objeto python.
Eu vou te dizer como fazer
esses objetos você mesmo sem uma função mais tarde.
Então, vamos armazenar nosso gerador em uma variável.
Nós vamos chamá-lo de "g", que é
um nome bastante popular para um gerador em um programa pequeno.
Se você tem muitos geradores,
claro, você terá que ir para um nome mais descritivo.
Então nós vamos imprimir o próximo valor
que o gerador nos daria.
Observe que quando você inicializa um gerador, assim,
ele não executa a função, ele começa no
topo sem executar nada.
Quando você pede o próximo valor, ele vai
até o rendimento e
lhe dará qualquer valor que você tenha gerado.
A maneira como você pede o
próximo valor, é que você não executa a função novamente, mas diz o próximo de "g".
Então, o próximo é uma função incorporada que afeta os geradores,
e diz para ele ir até o rendimento.
Ok, então se nós executarmos isso, você pode ver que agora nós
temos zero, porque esse é o primeiro número gerado.
Agora nosso gerador "g" parou aqui na
linha 4. 5 entre 4
e 5, por isso, se pedirmos outro número, note que, no final de
um programa, o gerador é destruído,
por isso, se rodarmos este programa novamente,
este será zero novamente e este será um agora.
Não se lembra das execuções de
programas, simplesmente não é como o Python funciona.
Então, agora podemos pedir o primeiro número e
depois o próximo número.
Após o primeiro número, ele será parado
entre quatro e cinco.
Quando dizemos em seguida, continua até o próximo rendimento,
o que significa repetir este loop uma vez e nos dá um.
OK.
Muito importante, a função lembra onde parou.
Então, a qualquer momento, você pode interromper a execução
da função e, em seguida, pode ligar para a próxima para continuar.
Portanto, não é útil apenas para gerar números ou o que quer que seja,
também é útil quando você quer impedir que uma função
seja executada temporariamente e, em seguida, pode
continuar a executá-la sempre
que quiser, chamando em seguida.
Então talvez não seja
algo que faça muito sentido agora, mas lembre-se
disso quando precisarmos disso quando fizermos uma programação sincronizada.
Então, e a função range?
Eu disse anteriormente que isso
estava explicando essencialmente como a função range funciona internamente, e isso é verdade,
mas a função
range não lhe dá um gerador diretamente.
Aqui, vamos fazer algo como "meu
objeto de intervalo", vai ser o
intervalo 10.
Isso se comporta muito parecido com um gerador, mas se
você chamar o próximo de "meu objeto
de intervalo", receberá um erro e verá isso.
Isso porque o objeto range não é bem um gerador, embora
se comporte dessa maneira, ele
não gere uma lista e, em seguida, permita
que você faça uma iteração sobre ele, ele se comporta dessa maneira de geração
para ser mais eficiente.
"Meu objeto de alcance",
no entanto, você pode lembrar
que imprimimos muito mais cedo
no curso e recebemos um intervalo estranho de zero a dez.
Isso é apenas a função "repr" sendo chamada, e como você
pode ver se imprimimos o resultado "repr", também vemos
o intervalo de zero a dez.
Então, "meu objeto de intervalo" é algo que
se comporta assim, vamos aprender
em alguns vídeos exatamente como podemos fazer uma iteração em um objeto para
que ele se comporte como um objeto de intervalo.
Então, nós aprendemos sobre esses geradores, e mais uma coisa que
eu queria mencionar, sobre os geradores
é que a função de lista pode transformar um gerador em uma lista.
Então, podemos imprimir lista de "g".
Aqui mesmo o que chamamos de "next" e "next"
novamente, e depois "list".
Então agora temos zero e um impresso para essas são as duas
coisas em nossas "próximas" funções,
e então geramos uma lista do
gerador, mas essa lista de curso continua de onde paramos.
O próprio gerador lembra o
que era, então a lista começa de dois, não de zero.
Então, é realmente importante lembrar em geradores, eles
se lembram de onde estavam.
Então, quando você cria um, é basicamente a partir do momento em que você começa a usá-lo, no
momento em que você começa a
chamar "próximo", ele se lembra de onde está, e
você não pode voltar atrás. OK.
Agora, nos próximos vídeos,
vamos aprender mais sobre geradores.
Vamos aprender sobre classes
de geração, como você pode criar uma classe que se
comporta como um gerador, e também aprenderemos sobre iteradores e iteráveis
no Python, e os objetivos do
intervalo são um exemplo disso.
Então, vamos passar
para alguns exemplos de programação
funcional, como filter, map, any e all, e enumerar.
Então, muito animado
para esta seção, estou confiante de que os geradores
serão algo de que você precisará no desenvolvimento
do Python, especialmente à medida que avançamos no curso.
Então, com isso dito, vejo vocês no próximo vídeo.