Planeta

  • Sérgio Silva
    Ainda haveria mais a dizer sobre os ciclos na linguagem de programação Python, mas acho que o principal ficou bem expresso nesta série de posts. Como conclusão: - Quando definimos uma classe, podemos torná-la iterável implementando o método especial __iter__(); - List comprehensions são uma forma compacta de criar listas sobre iteráveis. Permitem tornar o código muito conciso; ...


    Ver post completo




    "Ciclos em Python, conclusão" é um post originalmente publicado no blog Sergio Silva Blog

  • Sérgio Silva
    Ainda haveria mais a dizer sobre os ciclos na linguagem de programação Python, mas acho que o principal ficou bem expresso nesta série de posts. Como conclusão: - Quando definimos uma classe, podemos torná-la iterável implementando o método especial __iter__(); - List comprehensions são uma forma compacta de criar listas sobre iteráveis. Permitem tornar o código muito conciso; ...


    Ver post completo




    "Ciclos em Python, conclusão" é um post originalmente publicado no blog Em Python

  • Sérgio Silva
    A melhor forma de abstrair as nossas iterações é fazer os nossos próprios objectos iteráveis. Neste post veremos como podemos tornar os nossos objectos em iteráveis. ...


    Ver post completo




    "Ciclos em Python, como tornar os nossos objectos em Iteráveis" é um post originalmente publicado no blog Em Python

  • Sérgio Silva
    A melhor forma de abstrair as nossas iterações é fazer os nossos próprios objectos iteráveis. Neste post veremos como podemos tornar os nossos objectos em iteráveis. ...


    Ver post completo




    "Ciclos em Python, como tornar os nossos objectos em Iteráveis" é um post originalmente publicado no blog Sergio Silva Blog

  • Sérgio Silva
    Neste post vou falar um pouco sobre os mecanismos de baixo nível presentes na iteração da linguagem de programação Python. Existem dois tipos de objectos envolvidos na iteração. Até agora tenho falado nos iteráveis que são objectos que contêm um conjunto de valores. Os iteráveis não podem contudo ser percorridos directamente, para fazer isso é necessário solicitar ao iterável o iterador. ...


    Ver post completo




    "Ciclos em Python, operações de baixo nível" é um post originalmente publicado no blog Sergio Silva Blog

  • Sérgio Silva
    Neste post veremos outro exemplo da forma de repensarmos a iteração. Supondo que temos de percorrer uma estrutura bidimensional, como uma folha de cálculo. Uma forma de o fazer seria com dois ciclos um dentro do outro, o primeiro ciclo percorria as linhas e o segundo as colunas. As variáveis dos dois ciclos juntos seriam usadas para aceder ao conteúdo das células da folha de cálculo. ...


    Ver post completo




    "Ciclos em Python, Generators - parte 3" é um post originalmente publicado no blog Blogue pessoal de Sergio Silva

  • Sérgio Silva
    Os generatores são uma poderosa ferramenta, providenciada pela linguagem de programação Python, para a abstracção da iteração. Tal como as funções são boas para abstrair uma série de expressões, e as classes são boas para abstrair uma colecção de dados e métodos para os manipular, os generatores são bons para abstrair a iteração. ...


    Ver post completo




    "Ciclos em Python, Generators - parte 2" é um post originalmente publicado no blog sergiosilvablog.com

  • Sérgio Silva
    Os generators são uma forma de criar iteráveis através de uma função.

    Uma função normal retorna um valor com o uso da palavra return. Um generator é tal como uma função, mas em vez de usar a palavra return usa a palavra yield uma ou mais vezes (pode também usar a palavra return para sair da função). Ao chamar a função generator é criado um iterável, e ao iterar sobre o mesmo é executado o código do generetor. Cada vez que um yield é executado ele produz um novo valor no stream do iterável.


    def ola_mundo():
    yield "Ola"
    yield "mundo"

    for x in ola_mundo():
    print x


    Ola
    mundo



    Este pequeno exemplo ilustrativo de um generator, contém apenas duas chamadas da expressão yield. Ao iterarmos sobre a função ola_mundo() com um ciclo for verificamos que este generator produz uma stream de dois valores, "Ola" e "mundo".

    Os generatores normalmente não são assim tão simples, tipicamente o código de um generator terá um ciclo for com chamadas à expressão yield.


    def numeros_pares(stream):
    for n in stream:
    if n % 2 == 0:
    yield n

    for n in numeros_pares(nums):
    faz_algo(n)

    Podemos reescrever a função numeros_pares() como um generator. O código é praticamente o mesmo, mas em vez de produzir uma lista e devolvê-la no fim da função, simplesmente produz os valores assim que os encontra.

    Chamamos esta função numeros_pares() da mesma forma, passando-lhe o iterável que queremos que seja trabalhado e a função devolve-nos um iterador que produzirá os valores pares desse iterável.

    A função anterior de numeros_pares() construía uma lista de números pares que nos devolvia no fim, isso significa que nada mais acontecia no nosso programa enquanto a função não examinasse a sequência completa do iterável e seleccionasse os valores pares para a nova lista. Para um iterável pequeno isso poderá não ser um problema mas será certamente para um iterável grande.

    Já a versão generator da função devolverá o primeiro número par que encontrar deixando o nosso programa disponível para prosseguir com o seu trabalho antes que toda a sequência do iterável seja examinada. Isto significa que a função pode trabalhar indefinidamente ou mesmo com streams infinitas.

    Os generatores têm a vantagem de serem "preguiçosos", eles não "trabalham" até que o primeiro valor lhe seja pedido, e quando isso acontece limitam-se a dar esse valor e voltam a parar, não voltando a "trabalhar" até que o próximo valor seja pedido. Isto faz com que os generators usem poucos recursos e sejam mais indicados para certos tipos de iteráveis.

    Os generators podem ser inicialmente confusos, eles são muito semelhantes a funções mas têm diferenças importantes. Primeiro chamar um generator não faz com que o seu código seja imediatamente executado, ele simplesmente cria um iterável. Só quando um ciclo for ou outro "consumidor" do iterável começar a pedir valores do stream é que o código do generator começa a ser executado.

    Quando a expressão yield é encontrada, a execução é suspensa, e o valor é usado como o próximo valor da stream. Numa função normal a expressão return termina a função. Mas num generator o estado actual é memorizado e quando o próximo valor for solicitado, a execução do generator continua onde tinha ficado anteriormente, depois da expressão yield. O próximo valor da stream é produzido quando uma expressão yield é novamente executada. Todas as variáveis locais do generator mantêm os seus valores durante todo o percurso do stream. Isto torna os generatores muito convenientes para escrever iteráveis.

    O iterador termina quando o generator retorna, quer explicitamente com a expressão return, ou quando executa a última expressão do código do generator.




    A série de posts sobre ciclos em Python tem continuação nos próximos capítulos.




    A inspiração para este post veio daqui.


    "Ciclos em Python, Generators - parte 1" é um post originalmente publicado no blog sergiosilvablog.com

  • Sérgio Silva
    Já vimos nos posts anteriores o poder da iteração em Python, vamos agora ver neste post como podemos personalizar as nossa iterações.


    nums =[88, 73, 92, 72, 40, 38, 25, 20, 90, 72]
    for n in nums:
    if n % 2 == 0:
    faz_algo(n)

    def numeros_pares(stream):
    valores=[]
    for n in stream:
    if n % 2 == 0:
    valores.append(n)
    return valores

    for n in numeros_pares(nums):
    faz_algo(n)

    Uma forma de iteração indirecta é percorrer uma sequência de valores e entre eles escolher aqueles que nos interessam.

    Neste exemplo temos uma lista de números aos quais queremos fazer_algo() com os valores pares. No primeiro exemplo percorremos a lista num ciclo for e testamos se cada valor é par e só no caso de ser par realizamos a nossa operação fazer_algo().

    Uma alternativa seria escrever uma função que aceita uma sequência como argumento e produz a nova sequência que pretendemos. A função numeros_pares() faz isso. Itera sobre a lista que é enviada no argumento e devolve uma lista com os valores pares. Depois podemos usar essa lista num ciclo for para iterar directamente sobre os números pares.

    Este exemplo tem um problema porque cria na realidade uma nova lista, uma lista com números pares. Veremos no próximo post como evitar isso.



    A série de posts sobre ciclos em Python aproxima-se rapidamente do fim, mas continuará ainda a ser o assunto principal nos próximos posts.



    A inspiração para este post veio daqui.


    "Ciclos em Python, iteração personalizada" é um post originalmente publicado no blog sergiosilvablog.com

  • Sérgio Silva
    Outra dúvida recorrente quando se lida com a iteração é iterar sobre duas listas.

    Como vimos no post anterior (Ciclos em Python, problemas comuns e os índices) não precisamos de iterar sobre inteiros para indexar os valores numa iteração. Outro desafio numa iteração é como percorrer simultaneamente duas listas.


    cidades =['Aveiro', 'Braga', 'Porto', 'Lisboa']
    habitantes = [55291, 181894, 237584, 547631]
    for i in range(len(cidades)):
    cidade = cidades[i]
    populacao = habitantes[i]
    print ("{0} tem {1} habitantes".format(cidade, populacao))

    Aveiro tem 55291 habitantes
    Braga tem 181894 habitantes
    Porto tem 237584 habitantes
    Lisboa tem 547631 habitantes


    A geração de inteiros para percorrer os valores das listas pelos seus índices é uma forma de o fazer, mas mais uma vez não existe necessidade de gerar inteiros para executar esta tarefa.


    for cidade, populacao in zip(cidades, habitantes):
    print ("{0} tem {1} habitantes".format(cidade, populacao))

    Aveiro tem 55291 habitantes
    Braga tem 181894 habitantes
    Porto tem 237584 habitantes
    Lisboa tem 547631 habitantes

    A função zip() recebe dois iteréveis e junta-os num só, devolvendo um iterável de pares. Como se pode ver no exemplo acima, conseguimos obter o mesmo resultado que a versão que se socorre de inteiros.
    De reparar que como não usa indexação, a função zip() funciona com qualquer iterável e não apenas com listas.

    A função dict() recebe como argumento um stream de pares do tipo chave/valor e constrói um dicionário a partir deles. Se tivermos duas listas uma com as chaves, por exemplo com nomes de cidades e outra com os valores, por exemplo com o número de habitantes a função zip(cidades, habitantes) produzirá um stream de pares que poderá ser usado pela função dict dict(zip(cidades, habitantes)) para produzir um dicionário.


    cidades =['Aveiro', 'Braga', 'Porto', 'Lisboa']
    habitantes = [55291, 181894, 237584, 547631]
    populacoes_por_cidade = dict(zip(cidades, habitantes))

    print populacoes_por_cidade
    {'Lisboa': 547631, 'Braga': 181894, 'Aveiro': 55291, 'Porto': 237584}

    print max(populacoes_por_cidade.values())
    547631

    print max(populacoes_por_cidade.items(), key=lambda b: b[1])
    ('Lisboa', 547631)

    print max(populacoes_por_cidade, key=populacoes_por_cidade.get)
    Lisboa


    Supondo que temos um dicionário com cidades e o seu número de habitantes.

    Podemos utilizar a função max() para obter a maior população, o nome e a população da cidade com mais habitantes, ou apenas o nome da cidade mais populosa.

    A iteração em Python permite-nos obter informação útil através de uma única e concisa expressão.



    Os ciclos continuarão a ser o assunto principal dos próximos posts.



    A inspiração para este post veio daqui.


    "Ciclos em Python, iterar sobre duas listas" é um post originalmente publicado no blog sergiosilvablog.com