Skip to content

Latest commit

 

History

History
executable file
·
2813 lines (2001 loc) · 93.1 KB

File metadata and controls

executable file
·
2813 lines (2001 loc) · 93.1 KB
..  shortname:: Listas
..  description:: Tipo de dado lista em python

.. index:: lista, elemento, item, sequência, coleção

Listas

Uma lista (list) em Python é uma sequência ou coleção ordenada de valores. Cada valor na lista é identificado por um índice. O valores que formam uma lista são chamados elementos ou itens. Listas são similares a strings, que são uma sequência de caracteres, no entanto, diferentemente de strings, os itens de uma lista podem ser de tipos diferentes.

.. index:: lista aninhada; lista; aninhada

Valores em uma lista

Existem várias maneiras de se criar uma nova lista. A maneira mais simples é envolver os elementos da lista por colchetes ( [ e ]).

[10, 20, 30, 40]
["spam", "bungee", "swallow"]

O primeiro exemplo é uma lista de quatro inteiros. O segundo é uma lista de três strings. Como dissemos anteriormente, os elementos de uma lista não precisam ser do mesmo tipo. A lista a seguir contém um string, um float, um inteiro e uma outra lista.

["oi", 2.0, 5, [10, 20]]

Um lista em uma outra lista é dita aninhada (nested) e a lista mais interna é chamada frequentemente de sublista (sublist). Finalemente, existe uma lista especial que não contém elemento algum. Ela é chamada de lista vazia e é denotada por [].

Como você esperaria, podemos também atribuir listas a variáveis e termos listas como parâmetro de funções.

.. activecode:: chp09_01

    vocabulario = ["iteracao", "selecao", "controle"]
    numeros = [17, 123]
    vazia = []
    lista_mista = ["ola", 2.0, 5*2, [10, 20]]

    print(numeros)
    print(lista_mista)
    nova_lista = [numeros, vocabulario]
    print(nova_lista)


Teste seu entendimento

.. mchoicemf:: test_question9_1_1
   :answer_a: Falso
   :answer_b: Verdadeiro
   :correct: a
   :feedback_a: Diferentemente de strings, listas podem ser formadas por valores de tipos diferentes.
   :feedback_b: Listas são heterogêneas, o que significa que elas podem ter valores de tipos diferentes.

   Uma lista só pode conter números inteiros?


.. index:: índices de listas;, índices; list traversal


Comprimento de uma lista

Da mesma forma que occore com strings, a função len retorna o comprimento de uma lista (o número de elementos na lista). Entretanto, como listas podem conter itens que são listas, é importante notar que len somente retorna o comprimento da lista mais externa. Em outras palavras, sublistas de uma lista são consideradas como sendo um elemento simples quando contamos o comprimento da lista.

.. activecode:: chp09_01a

    uma_lista =  ["ola", 2.0, 5, [10, 20]]
    print(len(uma_lista))
    print(len(['spam!', 1, ['Brie', 'Roquefort', 'Pol le Veq'], [1, 2, 3]]))


Teste seu entendimento

.. mchoicemf:: test_question9_2_1
   :answer_a: 4
   :answer_b: 5
   :correct: b
   :feedback_a: len retorna o número de itens em uma lista, não o maior índice
   :feedback_b: Sim, a lista é formada por 5 itens.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [3, 67, "gato", 3.14, False]
   print(len(uma_lista))
   </pre>

.. mchoicemf:: test_question9_2_2
   :answer_a: 7
   :answer_b: 8
   :correct: a
   :feedback_a: Sim, existem 7 itens na lista, sendo que dois itens são listas.
   :feedback_b: len retorna o número de itens na lista. O número de itens nas sublistas não são contados.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [3, 67, "gato", [56, 57, "cachorro"], [ ], 3.14, False]
   print(len(uma_lista))
   </pre>


Acessando os elementos

A sintaxe para acessar um elemento de uma lista é a mesma usada para acessar um caractere de um string. Nós usamos o operador de indexação ( [] -- não confundir com a lista vazia). A expressão dentro dos conchetes especifica o índice. Lembrar que o índice do primeiro elemento é 0. Qualquer expressão que tenha como resultado um número inteiro pode ser usada como índice e como com strings, índices negativos indicarão elementos da direita para a esquerda ao invés de da esquerda para a direita.

.. activecode:: chp09_02

    numeros = [17, 123, 87, 34, 66, 8398, 44]
    print(numeros[2])
    print(numeros[9-8])
    print(numeros[-2])
    print(numeros[len(numeros)-1])

Teste seu entendimento

.. mchoicemf:: test_question9_3_1
   :answer_a: [ ]
   :answer_b: 3.14
   :answer_c: False
   :correct: b
   :feedback_a: O índice da lista vazia é 4.
   :feedback_b: Sim, 3.14 é o item de índice 5 já que o índice do primeiro elemento é 0 e sublistas contam com um elemento.
   :feedback_c: False é o item de índice 6.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [3, 67, "gato", [56, 57, "cachorro"], [ ], 3.14, False]
   print(uma_lista[5])
   </pre>

.. mchoicemf:: test_question9_3_2
   :answer_a: Error, you cannot use the upper method on a list.
   :answer_b: 2
   :answer_c: GATO
   :correct: c
   :feedback_a: uma_list[2] é o string 'gato' logo o método upper (maiúsculo) é legal.
   :feedback_b: 2 é o índice.  Nós querenos o item que tem esse índice.
   :feedback_c: Sim, o string 'gato' transformado pelo método upper em maiúsculo é GATO.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [3, 67, "gato", [56, 57, "cachorro"], [ ], 3.14, False]
   print(uma_lista[2].upper())
   </pre>

.. mchoicemf:: test_question9_3_3
   :answer_a: 56
   :answer_b: g
   :answer_c: gato
   :answer_d: Error, you cannot have two index values unless you are using slicing.
   :correct: b
   :feedback_a: Índices começam de 0 e não de 1.
   :feedback_b: Sim, o primeiro caractere do string de índice 2 é g.
   :feedback_c: 'gato' é o item de índice 2, mas devemos determinar ainda o caractere de índice 0.
   :feedback_d: Usar mais de um índice é correto.  Você deve ler da esquerda para a direita.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [3, 67, "gato", [56, 57, "cachorro"], [ ], 3.14, False]
   print(uma_lista[2][0])
   </pre>

Pertinência em uma Lista

in e not in são operadores booleanos ou lógicos que testam a pertinência (membership) em uma sequência. Já usamos esses operadores com strings e eles também funcionam aqui.

.. activecode:: chp09_4

    frutas = ["maca", "laranja", "banana", "cereja"]

    print("maca" in frutas)
    print("pera" in frutas)

Teste seu entendimento

.. mchoicemf:: test_question9_4_1
   :answer_a: True
   :answer_b: False
   :correct: a
   :feedback_a: Sim, 3.14 é um item da lista uma_lista.
   :feedback_b: Existem 7 itens na lista, 3.14 é um deles.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [3, 67, "gato", [56, 57, "cachorro"], [ ], 3.14, False]
   print(3.14 in uma_lista)
   </pre>

.. mchoicemf:: test_question9_4_2
   :answer_a: True
   :answer_b: False
   :correct: b
   :feedback_a: É retornado True apenas para itens na lista mais externa.  57 é um item de uma sublista.
   :feedback_b: Sim, 57 não é um item da lista mais externa.  57 é um item de uma sublista.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [3, 67, "gato", [56, 57, "cachorro"], [ ], 3.14, False]
   print(57 in uma_lista)
   </pre>


Concatenação e repetição

Novamente, como com strings, o operador + concatena listas. Analogamente, o operador * repete os itens em uma lista um dado número de vezes.

.. activecode:: chp09_5

    frutas = ["maca", "laranja", "banana", "cereja"]
    print([1, 2] + [3, 4])
    print(frutas + [6, 7, 8, 9])

    print([0] * 4)
    print([1, 2, ["ola", "adeus"]]*2)


É importante perceber que esses operadores criam novas listas a partir dos elementos da lista dada. Se você concatena uma lista com 2 itens com uma lista com 4 itens, você obterá uma nova lista com 6 itens (não uma lista com duas sublistas). Similarmente, repetição de uma lista de 2 itens 4 vezes resultará em uma lista com 8 itens.

Uma maneira de fazermos isto mais claro é executar uma parte desses exemplos no codelens. A medida que cada passo do código é executado, você verá as variáveis sendo criadas e as listas as quais elas se referem. Preste atenção particularmente ao rótulo (tag) id que é mostrado depois do descritor do tipo de dado (list (id = 12))). Em Python o id corresponde a um único identificador para aquele objeto particular. Você pode dizer se são objetos diferentes através da comparação dos seus ids.

.. codelens:: chp09_concatid

    frutas = ["maca", "laranja", "banana", "cereja"]
    num_lista = [6,7]

    nova_lista = frutas + num_lista

    zeros = [0] * 4



O comando nova_lista = frutas + num_lista cria uma nova lista de objetos com o contéudo da lista frutas seguido pelo conteúdo da lista num_lista. Podemos ver que está é uma lista nova olhando os ids. O id da nova_lista não e o mesmo que o das outras. É extremamente importante que você saiba quando está criando uma nova lista ou apenas alterando uma lista existente. Novamente, os ids podem ajudar nessa tarefa.

Python possui uma função nativa (build-in) que recebe um objeto como argumento e retorna o seu id. A função é comvenientemente chamada de id e tem um único parâmetro, o objeto que você está interessado em descobrir o id. Você pode ver no examplo abaixo que o id real é usualmente um número inteiro muito grande (correspondente a um endereço na memória).

>>> uma_lista = [4,5,6]
>>> id(uma_lista)
4300840544
>>>

Teste seu entendimento

.. mchoicemf:: test_question9_5_1
   :answer_a: 6
   :answer_b: [1,2,3,4,5,6]
   :answer_c: [1,3,5,2,4,6]
   :answer_d: [3,7,11]
   :correct: c
   :feedback_a: Concatenação não soma soma os comprimentos da listas.
   :feedback_b: Concatenação não reordena os itens.
   :feedback_c: Sim, uma nova lista com os itens da primeira lista seguidos pelos itens da segunda lista.
   :feedback_d: Concatenação não adiciona os itens da listas.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [1, 3, 5]
   outra_lista = [2, 4, 6]
   print(uma_lista + outra_lista)
   </pre>


.. mchoicemf:: test_question9_5_2
   :answer_a: 9
   :answer_b: [1, 1, 1, 3, 3, 3, 5, 5, 5]
   :answer_c: [1, 3, 5, 1, 3, 5, 1, 3, 5]
   :answer_d: [3, 9, 15]
   :correct: c
   :feedback_a: Repetição não multiplica o comprimento das listas. Ela repete os itens.
   :feedback_b: Repetição não repete cada item individualmente.
   :feedback_c: Sim, a lista é repetida 3 vezes inteiramente, uma vez atrás da outra.
   :feedback_d: Repetição não multiplica os itens da lista individualmente.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [1, 3, 5]
   print(uma_lista * 3)
   </pre>



Fatias de listas

A operação de fatiar (slice) que vimos com strings também pode ser aplicada sobre listas. Lembre que o primeiro índice indica o ponto do início da fatia e o segundo índice é um depois do final da fatia (o elemento com esse índice não faz parte da fatia).

.. activecode:: chp09_6

    uma_lista = ['a', 'b', 'c', 'd', 'e', 'f']
    print(uma_lista[1:3])
    print(uma_lista[:4])
    print(uma_lista[3:])
    print(uma_lista[:])

Teste seu entendimento

.. mchoicemf:: test_question9_6_1
   :answer_a: [ [ ], 3.14, False]
   :answer_b: [ [ ], 3.14]
   :answer_c: [ [56, 57, "cachorro"], [ ], 3.14, False]
   :correct: a
   :feedback_a: Sim, a fatia começa no item de índice 4 e termina no  último item da lista.
   :feedback_b: Não colocando o limite superior da fatia incluímos até o último item.
   :feedback_c: Índices começam de 0.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [3, 67, "gato", [56, 57, "cachorro"], [ ], 3.14, False]
   print(uma_lista[4:])
   </pre>


.. index:: mutável; atribuição de item; imutável

Listas são mutáveis

Diferentemente de strings, listas são mutáveis (mutable). Isto significa que podemos alterar um item em uma lista acessando-o diretamente como parte do comando de atribuição. Usando o operador e indexação (colchetes) à esquerda de um comando de atribuição, podemos atualizar um dos itens de uma lista.

.. activecode:: ch09_7

    frutas = ["banana", "maca", "cereja"]
    print(frutas)

    frutas[0] = "pera"
    frutas[-1] = "laranja"
    print(frutas)


Uma atribuição a um elemento de uma lista é chamada de atribuição a um item (item assignment). Atribuição a itens não funciona com strings. Lembre-se que strings são imutáveis.

Aqui está o mesmo exemplo com o codelens para que você possa executar comando após comando e veja as mudanças na lista de elementos.

.. codelens:: item_assign

    frutas = ["banana", "maça", "cereja"]

    frutas[0]  = "pera"
    frutas[-1] = "laranja"


Combinando uma atribuição com o operador de fatiamento podemos atualizar vários elementos de uma só vez.

.. activecode:: ch09_8

    uma_lista = ['a', 'b', 'c', 'd', 'e', 'f']
    uma_lista[1:3] = ['x', 'y']
    print(uma_lista)

Também podemosremover elementos de uma lista atribuindo a lista vazia a eles.

.. activecode:: ch09_9

    uma_lista = ['a', 'b', 'c', 'd', 'e', 'f']
    uma_lista[1:3] = []
    print(uma_lista)

Podemos inserir elementos em uma lista espremendo-os em uma fatia vazia na posição desejada.

.. activecode:: ch09_10

    uma_lista = ['a', 'd', 'f']
    uma_lista[1:1] = ['b', 'c']
    print(uma_lista)
    uma_lista[4:4] = ['e']
    print(uma_lista)

Teste seu entendimento

.. mchoicemf:: test_question9_7_1
   :answer_a: [4, 2, True, 8, 6, 5]
   :answer_b: [4, 2, True, 6, 5]
   :answer_c: Erro, é uma atribuição ilegal
   :correct: b
   :feedback_a: Atribuição de item não insere o novo item na lista.
   :feedback_b: Sim, o valor True é colocado na posição de índice 2 da lista, 8 é trocado por True.
   :feedback_c: Atribuição de item é permida em listas.  Listas são mutáveis.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [4, 2, 8, 6, 5]
   uma_lista[2] = True
   print(uma_lista)
   </pre>

.. index:: comando del; comando; del

Remoção em listas

Usando fatiamento para remover elementos de uma lista pode ser complicado, e portanto propagador de erros. Python oferece uma maneira alternativa que é mais legível. O comando del remove um elemento de uma lista usando a sua posição.

.. activecode:: ch09_11

    a = ['um', 'dois', 'três']
    del a[1]
    print(a)

    lista = ['a', 'b', 'c', 'd', 'e', 'f']
    del lista[1:5]
    print(lista)

Como você pode esperar, del também manipula índices negativos e produz um erro de execução se o índice estiver foram do intervalo da lista. Além disso, você pode usar uma fatia como argumento para del. Como é usual, fatias selecionam todos os elementos até, mas não incluindo, o segundo índice.

.. index:: operador is; is; objetos e valores

Objetos e referências

Se executamos as seguintes atribuições,

a = "banana"
b = "banana"

sabemos que a e b farão referência ao string "banana". Entretanto, ainda não sabemos se eles se referem ao mesmo string.

Existem duas possibilidades para o Python interpretar internamente essas atribuições:

List illustration

ou

List illustration

Em uma das interpretações a e b se referem a dois strings ou objetos diferentes que têm o mesmo valor. Na segunda interpretação, eles se referem ao mesmo objeto. Lembre-se que um objeto é uma valor ao qual uma variável pode se referir ou apontar.

Já sabemos que objetos podem ser identificados usando seus identificadores que são únicos. Podemos também testar se dois nomes se referem ao mesmo objeto usando o operador is. O operador is retorna True se as duas referências são ao mesmo objeto. Em outras palavras, as referências são a mesma. Teste esse conceito com os exemplos acima.

.. activecode:: chp09_is1

    a = "banana"
    b = "banana"

    print(a is b)

A resposta é True. Isto nos diz que ambos a e b se referem ao mesmo objeto, e que o segundo dos diagramas de referências descreve a relação. Como strings são imutáveis (immutable), Python optimiza recursos fazendo dois que se referem ao mesmo string se referirem ao mesmo objeto.

Este não é o caso com listas. Considere o exemplo seguir. Aqui a e b se referem a duas listas diferentes, cada uma por acaso tem os mesmo elementos como valores.

.. activecode:: chp09_is2

    a = [81, 82, 83]
    b = [81, 82, 83]

    print(a is b)

    print(a == b)

O diagrama de referências para este exemplo se parece com o seguinte.

Reference diagram for equal different lists

a e b tem o mesmo valor mas não se referem ao mesmo objeto.

Existe ainda um outro ponto importante a ser notado a respeito desse diagrama de referências. O valor a é uma referência a uma coleção de referências (collection of references). Essas referências na realidade se referem a valores inteiros em uma lista. Em outras palavras, um lista é uma coleção de referências para objetos. É interessante que apesar de a e b serem duas listas distintas (duas coleções de diferentes de referências), o objeto inteiro 81 é compartilhado por ambos. Como strings, inteiros são também imutáveis portanto Python optimiza e permite que todos compartilhem o mesmo objeto.

Aqui esta o exemplo no codelens. Preste atenção particularmente nos valores dos id.

.. codelens:: chp09_istrace
    :showoutput:

    a = [81, 82, 83]
    b = [81, 82, 83]

    print(a is b)
    print(a == b)


.. index:: aliases, apelidos

Apelidos (Aliasing)

Como variáveis fazem referência a objetos, se atribuimos uma variável a outra, ambas as variáveis passam a fazer referência ao mesmo objeto.

.. activecode:: listalias1

    a = [81, 82, 83]
    b = a
    print(a is b)

Nesse caso, o diagrama de referências se parece com:

State snapshot for multiple references (aliases) to a list

Como a mesma lista tem dois nomes diferentes, a e b, dizemos que a lista tem apelidos (aliased). Mudanças feitas com um apelido afeta o outro. No exemplo do codelens a seguir, os ids de a e b são os mesmos depois da execução do comando de atribuição b = a.

.. codelens:: chp09_is3
    :showoutput:

    a = [81, 82, 83]
    b = [81, 82, 83]

    print(a == b)
    print(a is b)

    b = a
    print(a == b)
    print(a is b)

    b[0] = 5
    print(a)


Apesar desse comportamento ser útil, ele é algumas vezes inesperado ou indesejável. Em geral, é mais seguro evitar apelidos (aliasing) quando você está trabalhando com objetos mutáveis. É evidente que com objetos imutáveis não há problema. Por isto, Python é livre para usar apelidos (alias) de strings e inteiros quando surge uma oportunidade para economizar espaço.

Teste seu entendimento

.. mchoicemf:: test_question9_10_1
   :answer_a: [4, 2, 8, 6, 5]
   :answer_b: [4, 2, 8, 999, 5]
   :correct: b
   :feedback_a: lista_b não é uma cópia de a_lista, ela é uma referência para a lista a qual lista_a faz referência.
   :feedback_b: Sim, como lista_a e lista_b fazem referência a mesma lista, mudança em uma também altera a outra.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   lista_a = [4, 2, 8, 6, 5]
   lista_b = lista_a
   lista_b[3] = 999
   print(lista_a)
   </pre>


.. index:: clone

Clonando listas

Se desejamos modificar uma lista e também manter uma cópia da lista original, temos que ser capazes de fazer uma cópia da lista, não apenas da referência. Este processo é algumas vezes chamado de clonar (cloning), para evitar a ambiguidade da palavra cópia.

A maneira mais fácil de clonarmos uma lista é usar o operador de fatiação.

Tomar qualquer fatia de a cria uma nova lista. Para clonar uma lista basta tomarmos a fatia como sendo a lista toda.

.. codelens:: chp09_is4
    :showoutput:

    a = [81, 82, 83]

    b = a[:]       # cria um clone com fatia
    print(a == b)
    print(a is b)

    b[0] = 5

    print(a)
    print(b)

Agora estamos livres para modicar b sem nos preocuparmos com a. Note também que o id de b é diferente do id de a. Ela é uma lista completamente diferente.

Repetições e referências

Já vimos que o operador de repetição trabalho sobre strings e também sobre listas. Por exemplo.

.. activecode:: repref1

    lista_original = [45, 76, 34, 55]
    print(lista_original*3)

Como uma lista, o operador de repetição cria cópias das referências. Apesar desse comportamento parecer simples, quando permitimos que uma lista ter referências a uma outra lista, podemos nos confrontar com alguns problemas sutis.

Considere a seguinte extensão do exemplo anterior.

.. activecode:: repref2

    lista_original = [45, 76, 34, 55]
    print(lista_original*3)

    lista_nova = [lista_original] * 3

    print(lista_nova)

lista_nova é uma lista com três referências para a lista_original que foram criadas pelo operador de repetição.

Repetition of a nested list

Agora, o que acontece se modificamos um valor da lista_original?

.. activecode:: repref3

    lista_original = [45, 76, 34, 55]

    lista_nova = [lista_original] * 3

    print(lista_nova)

    lista_original[1] = 99

    print(lista_nova)

lista_nova mostra a mudança em três lugares. Isto pode ser facilmente entendido através do diagrama de referências, já que existe apenas uma lista_original. Logo, qualquer alteração na lista_original aparece em cada uma das três referências da nova_lista.

Same reference

Aqui está o mesmo exemplo no codelens. Execute o código passo a passo e preste particular atenção à execução do comando de atribuição lista_original[1] = 99.

.. codelens:: reprefstep
    :showoutput:


    lista_original = [45, 76, 34, 55]

    lista_nova = [lista_original] * 3

    print(lista_nova)

    lista_original[1] = 99

    print(lista_nova)

Teste seu entendimento

.. mchoicemf:: test_question9_12_1
   :answer_a: [4, 2, 8, 999, 5, 4, 2, 8, 6, 5]
   :answer_b: [4, 2, 8, 999, 5]
   :answer_c: [4, 2, 8, 6, 5]
   :correct: c
   :feedback_a: print(lista_a) não print(lista_b)
   :feedback_b: lista_b é alterada, lista_a não é.
   :feedback_c: Sim, lista_a não foi alterada pela atribuição. lista_b é uma cópia das referência na lista a.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   lista_a = [4, 2, 8, 6, 5]
   lista_b = lista_a * 2
   lista_b[3] = 999
   print(lista_a)
   </pre>

.. mchoicemf:: test_question9_12_2
   :answer_a: [4,2,8,999,5,4,2,8,999,5]
   :answer_b: [[4,2,8,999,5],[4,2,8,999,5]]
   :answer_c: [4,2,8,6,5]
   :answer_d: [[4,2,8,999,5],[4,2,8,6,5]]
   :correct: b
   :feedback_a: [lista_a] * 2 cria uma lista contendo a lista_a repetida 2 vezes
   :feedback_b: Sim, lista_b contém duas referência, ambas para a lista_a.
   :feedback_c: print(lista_b)
   :feedback_d: lista_b contém duas referências, ambas para lista_a. Logo, alterações na lista_a aparecem em ambas as referências.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   lista_a = [4, 2, 8, 6, 5]
   lista_b = [lista_a] * 2
   lista_a[3] = 999
   print(lista_b)
   </pre>



.. index:: lista; concatenação; append


Métodos de listas

O operador ponto também pode ser usado para acessar métodos nativos (built-in) de objetos que são listas. append é um método de listas que insere o argumento passado para ele no final da lista. O exemplo a seguir mostra vários outros métodos. Alguns deles são muito fáceis de serem compreendidos.

.. activecode:: chp09_meth1

    minha_lista = []
    minha_lista.append(5)
    minha_lista.append(27)
    minha_lista.append(3)
    minha_lista.append(12)
    print(minha_lista)

    minha_lista.insert(1, 12)
    print(minha_lista)
    print(minha_lista.count(12))

    print(minha_lista.index(3))
    print(minha_lista.count(5))

    minha_lista.reverse()
    print(minha_lista)

    minha_lista.sort()
    print(minha_lista)

    minha_lista.remove(5)
    print(minha_lista)

    ultimo_item = minha_lista.pop()
    print(ultimo_item)
    print(minha_lista)

Existem duas maneiras de usar o método pop . A primeira, sem parâmetros, remove e retorna o último item da lista. Se for dado um argumento para a posição, pop remove e retorna o item da posição. De qualquer maneira a lista é alterada.

A tabela a seguir mostra um resumo dos métodos de listas mostrados acima. Faça testes com esses métodos para ganhar uma melhor compreensão do que eles fazem.

Método Parâmetros Resultado Descrição
append item mutador Acrescenta um novo item no final da lista
insert posição, item mutador Insere um novo item na posição dada
pop nenhum híbrido Remove e returno o último item
pop posição híbrido Remove e retorna o item da posição.
sort nenhum mutador Ordena a lista
reverse nenhum mutador Ordena a lista em ordem reversa
index item retorna idx Retorna a posição da primeira ocorrência do item
count item retorna ct Retorna o número de ocorrências do item
remove item mutador Remove a primeira ocorrência do item

Detalhes desses e de outros métodos podem ser vistos em Python Documentation.

É importante notar que append, sort, e reverse retornam None. Isto significa que atribuira a minha_lista o resultado da ordenação de minha_lista resultará na perda da lista.

.. activecode:: chp09_meth2

    minha_lista = []
    minha_lista.append(5)
    minha_lista.append(27)
    minha_lista.append(3)
    minha_lista.append(12)
    print(minha_lista)

    minha_lista = minha_lista.sort()   # possivel erro
    print(minha_lista)

Teste seu entendimento

.. mchoicemf:: test_question9_13_1
   :answer_a: [4, 2, 8, 6, 5, False, True]
   :answer_b: [4, 2, 8, 6, 5, True, False]
   :answer_c: [True, False, 4, 2, 8, 6, 5]
   :correct: b
   :feedback_a: True foi inserido primeiro, False foi inserido por último.
   :feedback_b: Sim, cada item é inserido no final da lista.
   :feedback_c: append insere um item no final da lista e não no início.

.. mchoicemf:: test_question9_13_2
   :answer_a: [False, 4, 2, True, 8, 6, 5]
   :answer_b: [4, False, True, 2, 8, 6, 5]
   :answer_c: [False, 2, True, 6, 5]
   :correct: a
   :feedback_a: Sim, primeiro True foi inserido na posição de índice 2, depois False foi inserido na posição 0.
   :feedback_b: insert coloca itens na posição especificada e desloca os itens à direita dessa posição.
   :feedback_c: insert não remove ou troca item algum.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [4, 2, 8, 6, 5]
   uma_lista.insert(2,True)
   uma_lista.insert(0,False)
   print(uma_lista)
   </pre>

.. mchoicemf:: test_question9_13_3
   :answer_a: [4, 8, 6]
   :answer_b: [2, 6, 5]
   :answer_c: [4, 2, 6]
   :correct: c
   :feedback_a: pop(2) remove o item na posição de índice 2, não remove o valor 2.
   :feedback_b: pop() remove o último item, não o primeiro.
   :feedback_c: Sim, primeiro 8 foi removido, depois o último item, que era 5.

.. mchoicemf:: test_question9_13_4
   :answer_a: [2, 8, 6, 5]
   :answer_b: [4, 2, 8, 6, 5]
   :answer_c: 4
   :answer_d: None
   :correct: c
   :feedback_a: uma_lista é agora o valor que foi retornado por pop(0).
   :feedback_b: pop(0) altera a lista removendo o último elemento.
   :feedback_c: Sim, primeiro 4 foi removido da lista, então retornado e atribuído a uma_lista.  A  lista foi perdida.
   :feedback_d: pop(0) retorna o primeiro item da list, logo uma_lista foi alterada.

Scratch Editor

.. actex:: scratch_9_1

Retorno a sistemas-L

Retornemos aos sistemas-L que foram introduzidos na capítulo anterior e trataremos de uma característica interessante que usa listas.

Suponha que temos a seguinte gramática:

X
X --> F[-X]+X
F --> FF

Este sistema-L é muito similar ao sistema-L já visto exceto que adicionamos uma mudança. Acrescentamos os caracteres '[' e ']'. O significado desses caracteres inclui uma nova dimensão bastante interessante ao nosso sistema-L. O caractere '[' indica que desejamos salvar o estado na nossa tartaruga, a saber a sua posição e sua sentido de tal maneira que possamos voltar a esta posição mais tarde. O ']' diz a tartaruga para voltar para a última posição salva. A maneira que utilizaremos para realizar essas tarefas será através do uso de listas. Podemos salvar a sentido e posição de uma tartaruga como uma lista de 3 elementos [sentido, x, y] . A primeira posição da lista armazena a sentido, a segunda armazena a coordenada x e a terceira a coordenada y.

Agora, se criarmos uma lista vazia e cada vez que virmos um '[' usarmos a função append para inserir no seu final a lista contendo [sentido, x, y] teremos um históricos das posições em que a tartaruga esteve. A última posição salva estará sempre no final da lista. Quando encontrarmos um ']' no string, usamos a função pop para remover a última informação inserida na lista.

Modifiquemos nossa função drawLsystem para iniciarmos a implementação do comportamento descrito.

.. activecode:: list_lsys1

    import turtle

    def drawLsystem(aTurtle,instructions,angle,distance):
        savedInfoList = []
        for cmd in instructions:
            if cmd == 'F':
                aTurtle.forward(distance)
            elif cmd == 'B':
                aTurtle.backward(distance)
            elif cmd == '+':
                aTurtle.right(angle)
            elif cmd == '-':
                aTurtle.left(angle)
            elif cmd == '[':
                savedInfoList.append([aTurtle.heading(),aTurtle.xcor(),aTurtle.ycor()])
                print(savedInfoList)
            elif cmd == ']':
                newInfo = savedInfoList.pop()
                print(newInfo)
                print(savedInfoList)
            else:
                print('Error:', cmd, 'is an unknown command')

    t = turtle.Turtle()
    inst = "FF[-F[-X]+X]+F[-X]+X"
    drawLsystem(t,inst,60,20)

Quando executamos este exemplo vemos que a figura não é muito interessante, mas note que é exibido e como salvamos a informação sobre as tartarugas e acrescentada e removida do final da lista. No próximo exemplo faremos uso da informação da lista para salvar e recuperar as posições da tartaruga e o seu sentido quando necessário. Usaremos um exemplo mais longo para que você tenha uma ideia de que tipo de desenho podemos obter através de um sistema-L.

.. activecode:: list_lsys2

    import turtle

    def drawLsystem(aTurtle,instructions,angle,distance):
        savedInfoList = []
        for cmd in instructions:
            if cmd == 'F':
                aTurtle.forward(distance)
            elif cmd == 'B':
                aTurtle.backward(distance)
            elif cmd == '+':
                aTurtle.right(angle)
            elif cmd == '-':
                aTurtle.left(angle)
            elif cmd == '[':
                savedInfoList.append([aTurtle.heading(),aTurtle.xcor(),aTurtle.ycor()])
                print(savedInfoList)
            elif cmd == ']':
                newInfo = savedInfoList.pop()
                aTurtle.setheading(newInfo[0])
                aTurtle.setposition(newInfo[1],newInfo[2])
            else:
                print('Error:', cmd, 'is an unknown command')

    t = turtle.Turtle()
    inst = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF[-FFFFFFFFFFFFFFFF[-FFFFFFFF[-FFFF[-FF[-F[-X]+X]+F[-X]+X]+FF[-F[-X]+X]+F[-X]+X]+FFFF[-FF[-F[-X]+X]+F[-X]+X]+FF[-F[-X]+X]+F[-X]+X]+FFFFFFFF[-FFFF[-FF[-F[-X]+X]+F[-X]+X]+FF[-F[-X]+X]+F[-X]+X]+FFFF[-FF[-F[-X]+X]+F[-X]+X]+FF[-F[-X]+X]+F[-X]+X]+FFFFFFFFFFFFFFFF[-FFFFFFFF[-FFFF[-FF[-F[-X]+X]+F[-X]+X]+FF[-F[-X]+X]+F[-X]+X]+FFFF[-FF[-F[-X]+X]+F[-X]+X]+FF[-F[-X]+X]+F[-X]+X]+FFFFFFFF[-FFFF[-FF[-F[-X]+X]+F[-X]+X]+FF[-F[-X]+X]+F[-X]+X]+FFFF[-FF[-F[-X]+X]+F[-X]+X]+FF[-F[-X]+X]+F[-X]+X"
    t.setposition(0,-200)
    t.left(90)
    drawLsystem(t,inst,30,2)


Em vez de usar o string inst fornecido aqui, use o código do capítulo String, e escreve suas próprias função applyRules para implementar o sistema-L. Este exemplo usa apenas 6 expansões. Teste com um número maior de expansões. Você também pode desejar executar com um exemplo com valores diferentes para o ângulo e a distância.

Scratch Editor

.. actex:: scratch_9_2

Append versus concatenação

O método append acrescenta um novo item no final da lista. É possível acrescentar um item no final da lista usando o operador + de concatenação. Entretanto, precisamos ser cuidadosos.

Considere o exemplo a seguir. A lista original contém 3 inteiros. Nós inserimos a palavra "gato" no final da lista.

.. codelens:: appcon1

    lista_orig = [45,32,88]

    lista_orig.append("gato")


Aqui usamos append que simplesmente modifica a lista. A fim de concatenar necessitamos usar o comando de atribuição:

lista_orig = [45, 32, 88]

lista_orig = lista_orig + ["gato"]

Note que a palavra "gato" necessita ser colocada em uma lista já que o operador concatenação exige duas listas para fazer o seu trabalho.

.. codelens:: appcon2

    lista_orig = [45, 32, 88]

    lista_orig = lista_orig + ["gato"]


É importante observar que com append, a lista original é simplemente modificada. É possível ver isto observando o id de lista_orig. O id é o mesmo antes e depois de executarmos append.

Por outro lado, com concatenação, você verá que o id da lista original não é o mesmo que o id da resultado depois do comando de atribuição. Execute um passo a passo cuidadoso de ambos os exemplos para notar a diferença. Com a concatenação um nova lista é criada.

Teste seu entendimento

.. mchoicemf:: test_question9_15_1
   :answer_a: [4, 2, 8, 6, 5, 999]
   :answer_b: Erro, não podemos concatenar uma lista e um inteiro.
   :correct: b
   :feedback_a: Você não pode concatenar uma lista e um inteiro.
   :feedback_b: Sim, para executarmos a concatenação necessitamos escrever uma_lista+[999].  Devemos ter duas listas.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [4, 2, 8, 6, 5]
   uma_lista = uma_lista + 999
   print(uma_lista)
   </pre>

.. index:: for loop, enumerate, comando for

.. index:: for loop, comando for

Listas e o laço for

É possível percorrermos uma lista (list traversal) iterando através de itens ou iterando através de índices.

.. activecode:: chp09_03a

    frutas = ["pera", "laranja", "banana", "cereja"]

    for uma_fruta in frutas:     # por item
        print(uma_fruta)


É quase como leríamos em linguagem natural: para (cada) fruta) em (a lista de) frutas, escreva (o nome da) fruta.

Podemos também usar o índice para acessar os itens iterativamente.

.. activecode:: chp09_03b

    frutas = ["pera", "laranja", "banana", "cereja"]

    for posicao in range(len(frutas)):     # por índice
        print(frutas[posicao])


Neste exemplo, em cada iteração do laço, a variável posição é usada como um índice da lista, imprimindo o posicao-ésimo item. Note que usamos len como limite superior do intervalo de tal forma que podemos iterar corretamente independentemente do número de itens na lista.

Qualquer expressão sequencial pode ser usada em um laço for. Por exemplo, a função range retornal uma sequência de inteiros.

.. activecode:: chp09_for3

    for numero in range(21):
        if numero % 3 == 0:
            print(numero)


Este exemplo exibe todos os multiplos de 3 entre 0 e 20.

Como listas são mutáveis, é frequentemente desejável que modifiquemos os elementos de uma lista a medida que ela é percorrida. No código a seguir todos os números inteiros entre 1 e 5 são elevados ao quadrado utilizando iteração por posição.

.. activecode:: chp09_for4

    numeros = [1, 2, 3, 4, 5]
    print(numeros)

    for i in range(len(numeros)):
        numeros[i] = numeros[i]**2

    print(numeros)

Para um minuto para refretir sobre range(len(numeros) até que você entenda como funciona. Estamos interessados aqui sobre ambos o valor e o índice de uma posição da lista de tal maneira que atribuir un novo valor à posição.

Scratch Editor

.. actex:: scratch_9_3

Teste seu entendimento

.. mchoicemf:: test_question9_16_1
   :answer_a: [4, 2, 8, 6, 5]
   :answer_b: [4, 2, 8, 6, 5, 5]
   :answer_c: [9, 7, 13, 11, 10]
   :answer_d: Erro, não podemos concatenar dentro de um append.
   :correct: c
   :feedback_a: 5 is adicionado a cada item antes que o append seja executado.
   :feedback_b: Existem muitos item na lista.  Somente 5 operações append são executadas.
   :feedback_c: Sim, o laço for processa cada item da lista: 5 is adicionado antes que o valor resultante seja inserido na nova lista.
   :feedback_d: 5 is adicionado a cada item da lista antes que a função append seja executada.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   lista = [4, 2, 8, 6, 5]
   nova_lista = [ ]
   for item in lista:
      nova_lista.append(item+5)
   print(nova_lista)
   </pre>

.. index:: parameter

.. index:: parametro

.. index:: side effect, modifier

.. index:: efeito colateral, modificador


Listas como parâmetros

Funções que recebem listas como argumentos e as alteram durante a execução são chamadas de modificadoras (modifiers) e as mudanças elas realizam são chamadas efeitos colaterais (side effects). Ao passar uma lista como argumento estamos realmente passando para a função uma referência para a lista e não um cópia (clone) da lista. Como listas são mutáveis as alterações feitas nos elementos referenciados pelos parâmetros mudarão a lista que o argumento está referenciando. Por exemplo, a função a seguir recebe uma lista como argumento e multiplica cada elemento da lista por 2:

.. activecode:: chp09_parm1

    def double_stuff(lista):
        """ (list) -> None
        Recebe uma lista referenciada por
        'lista' e sobreescreve cada
        elemento da lista com o dobro do
        seu valor.
        """
        for posicao in range(len(lista)):
            lista[posicao] = 2 * lista[posicao]

    things = [2, 5, 9]
    print(things)
    double_stuff(things)
    print(things)



O parâmetro lista e a variável (argumento) things são apelidos para o mesmo objeto.

State snapshot for multiple references to a list as a parameter

Como a lista de objetos é compartilhada por duas referências, existe apenas uma cópia. Se a função modifica os elementos da lista parâmetros, o função que fez a chamada também enxerga as alterações, já que as alterações estão ocorrendo no original.

This can be easily seen in codelens. Note that after the call to double_stuff, the id of the formal parameter uma_lista is the same as the id of things.

.. codelens:: chp09_parm1_trace

    def double_stuff(lista):
        """ (list) -> None
        Recebe uma lista referenciada por
        'lista' e sobreescreve cada elemento
        da lista com o dobro do seu valor.
        """
        for posicao in range(len(lista)):
            lista[posicao] = 2 * lista[posicao]

    things = [2, 5, 9]

    double_stuff(things)


.. index:: pure function

.. index:: função pura

Função pura

Uma função pura (pure function) não produz efeito colateral. Sua comunicação com a função que a chamou é somente através do parâmetros, que não são modificados e um valor é retornado. Aqui está um versão pura da função double_stuff da seção anterior. Para usar versão pura de double_stuff e modificar things, devemos atribuir o valor retornado a things :

.. activecode:: ch09_mod2

    def double_stuff(lista):
        """ (list) -> list
        Recebe uma lista referenciada por
        'lista' e cria e retorna uma nova
        lista em que cada elemento e' o
        dobro do valor correspondente
        na lista original.
        """
        nova_lista = []
        for valor in lista:
           novo_elemento = 2 * valor
           nova_lista.append(novo_elemento)
        return nova_lista

    things = [2, 5, 9]
    print(things)
    things = double_stuff(things)
    print(things)


Mais uma vez, codelens nos ajuda a ver as referências e os objetos passados como parâmetros e retornados.

.. codelens:: ch09_mod3

    def double_stuff(lista):
        """ (list) -> list
        Recebe uma lista referenciada por
        'lista' e cria e retorna uma nova
        lista em que cada elemento e' o
        dobro do valor correspondente
        na lista original.
        """
        nova_lista = []
        for valor in lista:
           novo_elemento = 2 * valor
           nova_lista.append(novo_elemento)
        return nova_lista

    things = [2, 5, 9]
    things = double_stuff(things)


Scratch Editor

.. actex:: scratch_9_4

Qual é melhor?

Tudo que é feito com uma função modificadora pode também ser realizado com uma função pura. De fato, algumas linguagens de programação somente permitem funções puras. Existe alguma evidência que programas que usam funções puras são desenvolvidos mais rapidamente e propagam menos erros que programas que usam funções modificadoras. No entanto, modificadoras são as vezes convenientes e em alguns casos, programas funcionais não menos eficientes.

Em geral, recomendamos que você escreva funções puras sempre que for razoável fazer isso é apele para modificadoras somente se existe uma boa vantagem em fazer isso. Este método pode ser chamado de estilo funcional de programação (functional programming style).

Funções que produzem listas

A versão pura da função double_stuff acima faz uso de um padrão (pattern) que você deve guardar na sua caixa de ferramentas. Sempre que você necessitar escrever uma função que cria e retorna uma lista, o padrão usualmente é:

inicialize uma variável para a lista nova com a lista vazia
itere
    crie um novo elemento
    append esse novo elemento a lista nova
retorne a lista nova

Vejamos outro uso desse padrão. Suponha que tenhamos uma função primo(x) que recebe um número inteiro x e retorna True se o valor de x é primo e False em caso contrário. Agora, escrevemos uma função que recebe um número inteiro n e cria e retorna uma lista com todos os números primos menores que n:

def primos_ate(n):
    """ (int) -> list
    Recebe um inteiro n e cria e retorna a lista dos números
    primos menores que n.
    """
    lista_primos = []
    for i in range(2,n):
        if primo(i):
            lista_primos.append(i);

    return lista_primos

List comprehensions

No exemplo anterior criamos uma lista de uma sequência de valores (os inteiros entre 2 e n) baseados em um critério de seleção (ser primo). Um maneira simples para realizar em Python esse tipo de processamento é o uso de list comprehension. (N.d.T. também traduzido para o português como abrangência de listas. Ver o comentário em: List comprehensions ou abrangências de listas.)

List comprehension é uma maneira compacta de criar listas. A forma geral para obter esse efeito é:

[<expressão> for <item> in <sequência> if <condição>]

onde a cláusula if é opcional. Por exemplo,

.. activecode:: list comprehension

    minha_lista = [1, 2, 3, 4, 5]

    sua_lista = [item ** 2 for item in minha_lista]

    print(sua_lista)

A expressão descreve cada elemento da lista que está sendo criada. A cláusula for itera sobre cada elemento da sequencia. Os itens são filtrados pela cláusula if se existe alguma. No exemplo acima, o comando for``faz com que a variável ``item assuma todos os valores na lista minha_lista. Cada item é elevado ao quadrado antes de ser inserido na lista que está sendo construída. O resultados é a lista dos quadrados dos valores em minha_lista.

Para escrever a função primos_ate usaremos a função primos como um filtro dos inteiros na sequência resultante de range. Em outras palavras, para cada inteiro de 2 até n, exclusive n, se o inteiro é primo, ele será mantido na lista resultante.

def primes_ate(n):
    """ (int) -> list
    Recebe um inteiro n e cria e retorna a lista dos números
    primos menores que n usando 'list comprehension'.
    """
    lista_primos = [num for num in range(2,n) if primo(num)]
    return lista_primos

Scratch Editor

.. actex:: scratch_9_5

Teste seu entendimento

.. mchoicemf:: test_question9_20_1
   :answer_a: [4, 2, 8, 6, 5]
   :answer_b: [8, 4, 16, 12, 10]
   :answer_c: 10
   :answer_d: [10].
   :correct: d
   :feedback_a: Item de uma_lista são dobrados antes de serem colocados em outra_lista
   :feedback_b: Nem todo os items em uma_lista são inseridos em outra_lista. Veja a cláusula if.
   :feedback_c: O resultado é do tipo list.
   :feedback_d: Sim, 5 é o único número ímpar em uma_lista.  Ele é dobrado antes de ser inserido em outra_lista.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   uma_lista = [4,2,8,6,5]
   outra_lista = [num*2 for num in uma_lista if num%2==1]
   print(outra_lista)
   </pre>

.. index:: nested list, list; nested

.. index:: lista aninhada, lista; aninhamento

Listas aninhadas

Uma lista aninhada (nested list) é uma lista que aparece como um elemento em uma outra lista. Nessa lista, o elemento com índice 3 é uma lista aninhada. Se executarmos print(lista[3]), obteremos [10, 20]. Para acessar um elemento de uma lista aninhada podemos proceder em dois passos. Primeiro, acessamos a lista aninhada, depois acessamos o item de interesse. Também é possível combinar esses passos usando o operador colchetes que são aplicados da esquerda para a direita.

.. activecode:: chp09_nest

    lista = ["oi", 2.0, 5, [10, 20]]
    lista_aninhada = lista[3]
    print(lista_aninhada)
    item = lista_aninhada[1]
    print(item)

    print(lista[3][1])


.. index:: matrix

Teste seu entendimento

.. mchoicemf:: test_question9_21_1
   :answer_a: 6
   :answer_b: 8
   :answer_c: 888
   :answer_d: 999
   :correct: c
   :feedback_a: 6 está na lista errada.  lista[1] se refere ao segundo item de lista, a saber [888,999].
   :feedback_b: 8 esta na lista errada.  lista[1] se refere ao segundo item de lista, a saber [888,999].
   :feedback_c: Sim, lista[0][1][0] é True e lista[1] é a segunda lista, o primeiro item é 888.
   :feedback_d: lista[0][1][0] is False.  Olhe novamente o comando.

   O que é impresso pelo trecho de código a seguir?

   <pre>
   lista = [ [4, [True, False], 6, 8], [888, 999] ]
   if lista[0][1][0]:
      print(lista[1][0])
   else:
      print(lista[1][1])
   </pre>

.. index:: strings and lists, split, join

.. index:: strings e listas, split, join

Strings e listas

Dois dos métodos mais úteis que operam sobre strings envolvem listas de strings. O método split quebra um string em uma lista de palavras. Por palavra entenda-se um string limitado por um conjunto de caracteres pré-definidos. Em caso de omissão (default), qualquer número de caracteres brancos (whitespace characters) é considerado como limite de uma palavra.

.. activecode:: ch09_split1

    musica = "Eduardo e Monica um dia se encontraram sem querer..."
    lista_palavras = musica.split()
    print(lista_palavras)

Um argumento opcional chamado de delimitador (delimiter) pode ser usado para especificar quais caracteres serão usados como fronteira de palavras. No exemplo a seguir usamos o string "se"

.. activecode:: ch09_split2

    musica = "Eduardo e Monica um dia se encontraram sem querer..."
    lista_palavras = musica.split("se")
    print(lista_palavras)

Note que o delimitador não aparece no resultado.

O método join faz o trabalho inverso do método split. Determinamos um string separador (separator), frequentemente chamado de cola (glue) e juntamos os elementos na lista utilizando a cola entre cada par de elemento.

.. activecode:: ch09_join

    lista = ["vermelho", "azul", "verde"]
    cola = ';'
    s = cola.join(lista)
    print(s)
    print(lista)

    print("***".join(lista))
    print("".join(lista))


A lista que estamos grudando (lista no exemplo) não é modificada. É possível utilizar qualquer string como cola, inclusive o string vazio.

Scratch Editor

.. actex:: scratch_9_6

Teste seu entendimento

.. mchoicemf:: test_question9_22_1
   :answer_a: Jesus
   :answer_b: CarolinaMariadeJesus
   :answer_c: CMdJ
   :answer_d: Clarice Lispector
   :correct: c
   :feedback_a: lista_de_nomes é a lista com as palavras no nome.
   :feedback_b: Muitos caracteres.  Deveria conter apenas uma letra de cada nome.
   :feedback_c: Sim, split cria uma lista com quatro palavras. O laço for itera sobre cada palavra criando um string com o primeiro caractere de cada uma.
   :feedback_d: Isso não faz sentido, mas ambas são excelentes escritoras.


   O que é impresso pelo trecho de código a seguir?

   <pre>
   escritora = "Carolina Maria de Jesus"
   lista_de_nomes = escritora.split()
   inic = ""
   for nome in lista_de_nomes:
      inic = inic + nome[0]
   print(inic)
   </pre>


Função de conversão list

Python possui uma função nativa chamada list que procura converter o seu argumento para o tipo list.

.. activecode:: ch09_list1

    xs = list("Crunchy Frog")
    print(xs)


O string "Crunchy Frog" é transformado em uma lista que contem cada caractere do string. Em geral, qualquer sequência pode ser convertida em uma lista usando esta função. O resultado sera a lista contendo os elementos na sequência original. Não é válido usar a função list sobre qualquer argumento que não seja uma sequência.

É importante observar que a função de conversão list colocará cada elemento da sequência original em uma nova lista. Quando estamos trabalhando com strings isto é muito diferente do resultado do método split. Enquanto que split quebra uma string em um lista de "palavras", list sempre quebra o string em uma lista de caracteres.

.. index:: tuples

.. index:: tuplas

Tuplas e mutabilidade

Até agora vimos dois tipos de coleções sequenciais de objetos: strings, que são compostos de caracteres; e listas. que são formados por elementos de um qualquer tipo. Uma das diferenças que notados é que os elementos de uma lista podem ser modificados, mas os caracteres de um string não podem. Em outras palavras, strings são imutáveis (immutable) e listas são mutáveis (mutable).

Uma tupla (tuple), como uma lista, é um sequência de items de qualquer tipo. Entretanto, diferentemente de listas, tuples são imutáveis. Sintaticamente, uma tupla é uma sequência de valores separadas por uma vírgula. Apesar de não ser necessário, há a convenção de se envolver uma tupla entre parêntese:

fernanda = ("Fernanda", "Montenegro", 1929, "Central do Brasil", 1998, "Atriz", "Rio de Janeiro, RJ")

Tuplas são úteis para representarmos o que em outras linguagens frequentemente chamamos de registros (records) --- alguma informação relacionada, como o seu histórico escolar, Não há descrição do que cada um desses campos (fields) significam, mas podemos ter um palpite. Uma tupla nos permite agruparmos informações relacionadas e usá-la como um único objeto.

Tuplas admitem a mesma sequência de operações que strings e listas. Por exemplo, com o operador de indexação selecionamos um elemento de uma tupla.

Como strings, se tentarmos utilizar o operador de atribuição para modificarmos um elemento da tupla, obteremos um erro.

fernanda[0] = 'X'
TypeError: 'tuple' object does not support item assignment

É claro que, mesmo que não seja possível modificarmos os elementos de uma tupla, nós podemos fazer com que uma variável faça referência a uma nova tupla que armazena indormações diferentes. Para construirmos uma nova tupla é conveniente que utilizemos fatiamento para selecionar as partes da tupla original e juntemos com outras informações a fim de obtermos uma nova tupla. Assim, fernanda tem um filme mais recente e nós podemos desejar alterar a sua tupla. Podemos facilmente usar fatiar as partes da tupla original que desejamos concatenar a fim de obtermos uma nova tupla.

.. activecode:: ch09_tuple1


    fernanda = ("Fernanda", "Montenegro", 1929, "Central do Brasil", 1998, "Atriz", "Rio de Janeiro, RJ")
    print(fernanda[2])
    print(fernanda[2:6])

    print(len(fernanda))

    fernanda = fernanda[:3] + ("Boa Sorte", 2014) + fernanda[5:]
    print(fernanda)

Para criar uma tupla com um único elemento (mas você provavelmente não fará isso frequentemente), podemos incluir no final uma vírgula, já que sem a vírgula no final, Python tratará (5) abaixo como um número inteiro entre parenteses:

.. activecode:: chp09_tuple2

    tup = (5,)
    print(type(tup))

    x = (5)
    print(type(x))


.. index::
    single: assignment; tuple
    single: tuple; assignment

.. index::
    single: atribuição; tupla
    single: tupla; atribuição

Atribuição de tuplas

Python tem um mecanismo muito poderoso de atribuição de tuplas (tuple assignment) que permite uma tupla de variáveis na esquerda receber valore de uma tupla de variáveis a direita do operador = de atribuição.

(nome, sobrenome, ano_de_nascimento, filme, ano_do_filme, profissao, local_de_nascimento) = fernanda

Isso é equivalente a sete comandos de atribuição, tudo em um linha e de maneira simples. Um requisito é que o número de variáveis a esquerda deve ser o mesmo que o número de valores na tupla.

Frequentemente, é útil trocarmos os valores de duas variáveis. Com o comando de atribuição convencional necessitamos de uma variável temporária. Por exemplo, para trocar os valores de a e b:

temp = a
a = b
b = temp

Atribuição entre tuplas faz o mesmo serviço de uma maneira muito elegante:

(a, b) = (b, a)

Naturalmente, o número de variáveis a esquerda e o número de valores a direita devem ser o mesmo.

>>> (a, b, c, d) = (1, 2, 3)
ValueError: need more than 3 values to unpack
.. index::
    single: tuple; return value

.. index::
    single: tupla; valor de retorno

Tuplas como valor de retorno

Funções podem retornar tuplas como valor de retorno. Isto é muito conveniente --- frequentemente desejamos saber qual foi o maior número de gols marcados e o maior número de gols sofridos por um time, ou desejamos o média e desvio padrão de um conjunto de dados, ou sejamos saber um dia, mês e ano ou se estamos fazendo alguma modelagem ecológica desejamos saber o número de coelho e lobos em uma ilha em um certo momento. Em cada um desses casos, uma função (que só pode retornar um único valor), pode cria uma tupla formada por vários valores.

Por exemplo, podemos escrever uma função que retorna a área de um círculo e comprimento de uma circunferência de um dado raio.

.. activecode:: chp09_tuple3


    def circInfo(r):
        """ (numero) -> (float,float)
        Recebe um numero r e retorna o comprimento da circunferencia
        de raio r e a area do circulo de raio r.
        """
        c = 2 * 3.14159 * r
        a = 3.14159 * r * r
        return (c, a)

    print(circInfo(10))


Scratch Editor

.. actex:: scratch_9_7

Glossário

.. glossary::


    apelidos (*aliases*)
        Várias variáveis fazendo referência a um mesmo objeto.


    clonar (*clone*)
        Criar um novo objeto com os mesmo valores de um objeto existente.
        Copiar uma referência de um objeto cria um apelido mas *não* cria um
        clone do objeto.



    delimitador (*delimiter*)
        Um caractere ou string usado para indicar onde um string deve ser
        "quebrado".

    efeito colateral (*side effect*)
        Um mudança no estado de um programa feito por uma função que foi invocada
        que não é o resultado do valor retornado pela função. Efeitos colaterais
        só podem ser produzidos por função midificadoras.

    elemento
        Um dos valores em uma lista (ou outra sequência). O operador colchetes
        seleciona elementos de uma lista.

    função pura (*pure functon*)
        Uma função que não produz efeitos colaterais. Funções puras apenas
        alteram os estado (variáveis) das funções que a chamam através de
        valores de retorno.

    índice (*index*)
        Uma variável, valor ou expressão do tipo ``int`` que indica um elemento de
        uma lista, string ou tupla.

    lista (*list*)
        Uma coleção de objetos, onde cada objeto é identificado por um índice.
        Como outros tipos ``str``, ``int``, ``float``, etc. existe também
        a função ``list`` que procura converter o seu argumento para uma
        lista.

    lista aninhada (*nested list*)
        Uma lista que é um elemento de uma outra lista.

    modificadora (*modifier*)
        Uma função que altera os seus argumntos. Somente argumentos de tipos
        mutáveis podem ser alterados por funções modificadoras.

    objeto (*object*)
        Um valor a que uma variável pode se referir.

    percorrer um lista (*list traversal*)
        Acesso sequencial a cada elemneto em uma lista.

    padrão (*pattern*)
        Uma sequência de comandos ou um estilo de escrever código que é
        potencialmente aplicável em várias situações. Parte de se tornar
        um cientista da computação madura está em aprender e estabelecer
        padrões e algoritmos que formam a sua caixa de ferramentas. Padrões
        frequentemente correspondem ao seu "mental chunking".

    sequência (*sequence*)
        Qualquer tipo de dados que consiste de uma coleção ordenada de elementos,
        com cada elemento identificado por um índice.

    tipo de dado mutável (*mutable data type*)
        Um tipo de dado em que seu elementos podem ser modificados. Todos os
        tipos mutáveis são compostos por outros tipos. Listas são mutáveis;
        strings e tuplas não são mutáveis.




Exercícios

  1. Desenhe um diagrama de referências para a e b antes e depois de ser executada a terceira linha do seguinte trecho de código:

    a = [1, 2, 3]
    b = a[:]
    b[0] = 5
  2. Cria uma lista chamada minha_lista com os seguinte items: 76, 92.3, "oi", True, 4, 76.

    .. actex:: ex_9_2
    
    
    
  3. Escreva comandos para:

    1. Inserir "pera" e 76 no final da lista.
    2. Inserir o valor "gato" na posição de índice 3.
    3. Inserir o valor 99 no início da lista.
    4. Encontrar o índice de "oi".
    5. Contar o número de ocorrências de 76 na lista.
    6. Remover a primeira ocorrência de 76 da lista.
    7. Remover True True da lista usando pop e index.
    .. actex:: ex_9_3
    
    
    
  4. Crie uma lista contendo 100 números inteiros aleatórios entre 0 e 1000 (usando iteração, ´´append´´ e o módulo random). Escreva uma função media que recebe uma lista de números como parâmetros e retorna a média dos valores na lista.

    .. actex:: ex_9_4
    
    
  5. Escreva uma função que recebe a lista de inteiros do exercício anterior e retorna o maior valor na lista. (Observação: existe uma a função nativa max que faz o serviço, mas você não deve usá-la.)

    .. actex:: ex_9_5
    
    
    
  6. Escreva uma função soma_de_quadrados(xs) que recebe uma lista de números xs e retorna a soma dos quadrados dos números na lista. Por exemplo soma_dos_quadrados([2, 3, 4]) deve retorna 4+9+16 que é 29.

    .. actex:: ex_7_11
    
    
  7. Escreva uma função que recebe uma lista de números inteiros e retorna a quantida de números ímpares na lista.

    .. actex:: ex_9_6
    
    
  8. Escreva uma função que recebe uma lista de números inteiros e retorna a soma dos números pares na lista.

    .. actex:: ex_9_7
    
    
  9. Escreva uma função que recebe uma lista de números e retorna a soma dos números negativos na lista.

    .. actex:: ex_9_8
    
    
  10. Escreva uma função que recebe uma lista de palavras (strings) e retorna o número de palavras na lista que tem comprimento 5.

    .. actex:: ex_9_9
    
    
  11. Escreva uma função que recebe uma lista de números inteiros e retorna a soma dos números na lista exclusive o primeiro número par.

    .. actex:: ex_9_10
    
    
    
  12. Escreva uma função que recebe uma lista de palavras (strings) e retorna o número de palavras que ocorre na lista até e inclusive a primeira ocorrência da palavra "sam".

    .. actex:: ex_9_11
    
    
    
  13. Apesar de Python nós fornecer uma grande lista de métodos nativos é uma boa prática e instrutivo pensar sobre como elas podem ser implementadas. Implemente uma função que se comporte como:

    1. count
    2. in
    3. reverse
    4. index
    5. insert
    .. actex:: ex_9_12
    
    
  14. Escreva uma função troca(s, velho, novo) que recebe os strings s, velho e novo e troca em s todas as ocorrências de velho por novo:

    test(troca('Mississippi', 'i', 'I'), 'MIssIssIppI')
    
    s = 'I love spom!  Spom is my favorite food.  Spom, spom, spom, yum!'
    test(troca(s, 'om', 'am'),
           'I love spam!  Spam is my favorite food.  Spam, spam, spam, yum!')
    
    test(troca(s, 'o', 'a'),
           'I lave spam!  Spam is my favarite faad.  Spam, spam, spam, yum!')
    

    Dica: use os métodos split e join.

    .. actex:: ex_9_13
    
    
  15. Aqui estão as regras para um sistema-L que cria algo que lembra um jardim comum de evas. Implemente as regras a seguir e teste-as. Use o ângulo de 25.7 graus.:

    H
    H --> HFX[+H][-H]
    X --> X[-FFF][+FFF]FX
    
    .. actex:: ex_9_14
    
    
  16. Aqui está outro sistema-L. Use o ângulo de 25 graus:

    F
    F --> F[-F]F[+F]F
    
    .. actex:: ex_9_15