MAC0216 - Técnicas de Programação I

Aula 23 - Introdução à Python

Tipos sequenciais

Python possui vários tipos de dados que armazenam sequências. Exemplos deles são:

  • list - sequências mutáveis e heterogêneas
  • tuple - sequências imutáveis e heterogêneas
  • str - sequências imutáveis e homogêneas (de caracteres)
  • bytes - sequências imutáveis e homogêneas (de dados binários)
  • bytearray - sequências mutáveis e homogêneas (de dados binários)

Listas (list) e tuplas (tuple) podem conter sequências de valores de qualquer tipo. Inclusive, uma sequência desses tipos pode ser heterogênea, ou seja, pode conter valores de diferentes tipos. Esses tipos de sequência guardam apenas as referências para os valores, por isso são mais flexíveis.

Nesta aula, veremos mais detalhes sobres os tipos list e str.

Listas (tipo list)

Uma lista (tipo list) em Python é uma sequência de valores de qualquer tipo ou classe tais como int, float, bool, str e mesmo list, entre outros.

Existem várias maneiras de se criar uma lista. A maneira mais simples é envolver os elementos da lista por colchetes ([ e ]). Por exemplo, podemos criar uma lista contendo os anos de obtenção das 5 primeiras conquistas do Brasil em Copas do Mundo de Futebol da seguinte maneira:

In [1]:
anos_conquistas = [1958, 1962, 1970, 1994, 2002] 
print(type(anos_conquistas))    
print("O conteúdo da lista é:", anos_conquistas)
print("A quantidade de elementos da lista é:", len(anos_conquistas))
<class 'list'>
O conteúdo da lista é: [1958, 1962, 1970, 1994, 2002]
A quantidade de elementos da lista é: 5

Para obter o comprimento de uma lista (ou seja, o número de elementos que a lista possui) usamos a função len() (de length), como mostrado no exemplo acima.

[] denota uma lista vazia, ou seja, uma lista que não contém nenhum elemento. O comprimento de uma lista que não contém nenhum elemento é 0.

In [2]:
lista_vazia = []     # cria uma lista vazia, ou seja com nenhum elemento dentro dela
print("O conteúdo da lista é:", lista_vazia)
print("A quantidade de elementos da lista é:", len(lista_vazia))
O conteúdo da lista é: []
A quantidade de elementos da lista é: 0

Usando o operador * conseguimos criar rapidamente listas de um determinado comprimento contendo elementos iguais. Veja os exemplos.

In [3]:
lista1 = [3] * 10   # criar uma lista contendo 10 elementos, todos de valor 3
tamanho = len(lista1) 
print("Lista com", len(lista1), "elementos de valor 3:", lista1)
print()
lista2 = [1,2,3] * 5 
print("Lista com 5 subsequências repetidas:", lista2)
Lista com 10 elementos de valor 3: [3, 3, 3, 3, 3, 3, 3, 3, 3, 3]

Lista com 5 subsequências repetidas: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]

Ao contrário do conceito de vetores em linguagem C, que são coleções indexadas homogêneas de dados (todos elementos do vetor são de um mesmo tipo), as listas em Python podem conter vários tipos de dados, sendo, portanto, possível armazenar coleções heterogêneas de dados.

Veja o exemplo a seguir:

In [4]:
lista = ["Fulano de tal", 21, 78266123, "Bacharelado em Ciência da Computação"]
print("Lista com elementos de diferentes tipos:", lista)
Lista com elementos de diferentes tipos: ['Fulano de tal', 21, 78266123, 'Bacharelado em Ciência da Computação']

Usamos l[i] para nos referir à posição de número (= índice) i em uma lista l, sendo que a primeira posição de uma lista é a de índice 0, a segunda é a de índice 1, e assim por diante, até a última posição da lista - que tem índice len(l)-1. Veja os exemplos a seguir:

In [5]:
lista = [10, 20, 30, 40, 50]
print(lista[0])      # mostra o valor do primeiro elemento da lista
print(lista[2])
print(lista[4])      # mostra o valor do último elemento da lista
print(lista[len(lista)-1])   # também mostra o valor do último elemento da lista
10
30
50
50

Podemos usar números negativos como índices para acessar as posições de uma lista na ordem reversa, ou seja, do fim para o início. O índice -1 se refere a última posição da lista, o -2 se refere à penúltima posição, e assim por diante.

In [6]:
lista5 = [10, 20, 30, 40, 50]
print(lista5[-1])             # mostra o valor do último elemento da lista
print(lista5[-len(lista5)])   # mostra o valor do primeiro elemento da lista
50
10

Também é possível modificar o valor de uma posição específica da lista:

In [7]:
lista6 = [10, 20, 30]
print(lista6)
lista6[0] = 5      # altera o valor da primeira posição da lista
lista6[-1] //= 2   # altera o valor da última posição da lista
print(lista6)
[10, 20, 30]
[5, 20, 15]

Quando tentamos acessar uma posição que não existe na lista, um erro de execução list index out of range é gerado:

In [8]:
lista7 = [10, 20]
print(lista7[2])   # tenta exibir o valor de uma posição que não existe na lista
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-8-85bd1f1d378d> in <module>
      1 lista7 = [10, 20]
----> 2 print(lista7[2])   # tenta exibir o valor de uma posição que não existe na lista

IndexError: list index out of range

Podemos usar a função append() para acrescentar novos elementos em uma lista. Para acrescentar o elemento x ao final de uma lista l, fazemos l.append(x). Veja os exemplos a seguir:

In [9]:
lista8 = [40]
print("Estado inicial da lista: ", lista8)
lista8.append(10)
print("Estado da lista depois da primeira inclusão de um novo elemento: ", lista8)
lista8.append(30)
print("Estado da lista depois da segunda inclusão de um novo elemento: ", lista8)
Estado inicial da lista:  [40]
Estado da lista depois da primeira inclusão de um novo elemento:  [40, 10]
Estado da lista depois da segunda inclusão de um novo elemento:  [40, 10, 30]

Percorrendo elementos com o for elemento in lista

Embora os elementos de uma lista também possam ser percorridos por meio de um laço tradicional (os que vimos nas aulas anteriores), existe um tipo de laço for especial para percorrer todos os elementos de uma lista, começando do seu início para o fim. A estrutura desse laço é

for elemento in lista:

onde elemento é o nome da variável que receberá um elemento da lista e lista é uma lista de elementos. Exemplo:

In [10]:
lista9 = [10, 20, 30, 40]
soma = 0
for numero in lista9:
    print(numero)
    soma += numero
print("A soma é", soma)
10
20
30
40
A soma é 100

Finalmente, o operador in nos permite verificar se um dado valor está em uma lista. A expressão

valor in lista

devolve True se valor for um elemento de lista, e False no caso contrário.

In [11]:
lista10 = [0,2,4,6,8,10]
print(lista10)
if 4 in lista10:
    print("O valor 4 está na lista.")
if 3 not in lista10:
    print("O valor 3 não está na lista.")
[0, 2, 4, 6, 8, 10]
O valor 4 está na lista.
O valor 3 não está na lista.

Obs.: Tanto o laço for ... in ... quanto os operadores in e not in podem ser usados com outros tipos de sequências (como str e tuple) além das listas.

Problema

Dados n > 0 e uma sequência com n números reais, imprimi-los na ordem inversa à da leitura.

Obs.: Este problema corresponde ao exercício 1 da lista de exercícios sobre vetores.

Solução

In [12]:
#--------------------------------------------
# Programa principal
def main():
    print ("Lê n números reais e imprime-os em ordem reversa")
    n = int(input("Digite n: "))
    cont = 0
    seq = []  # cria uma lista vazia

    for i in range(n):
        num = float(input("Digite um número da sequência: "))
        seq.append(num)   # coloca num no final da lista

    print("Sequência original: ", seq)


    print("Solução 1: usando índices decrescentes")
    for i in range(n-1,-1,-1):  
        print(seq[i], end = ' ')
    print ()

    # ou ainda, usando índices negativos
    print("Solução 2: usando índices negativos")
    cont = -1
    for i in range(1,n+1):
        print(seq[-i], end = ' ')
        
    print()
    
#--------------------------------------------    
main()
Lê n números reais e imprime-os em ordem reversa
Digite n: 5
Digite um número da sequência: 10
Digite um número da sequência: 20
Digite um número da sequência: 30
Digite um número da sequência: 40
Digite um número da sequência: 50
Sequência original:  [10.0, 20.0, 30.0, 40.0, 50.0]
Solução 1: usando índices decrescentes
50.0 40.0 30.0 20.0 10.0 
Solução 2: usando índices negativos
50.0 40.0 30.0 20.0 10.0 

No Python, é possível usar a função reverse() de um objeto do tipo list para inverter a ordem dos elementos de uma lista. Mas é preciso ter cuidado ao usar essa função, por que ela modifica a lista a partir da qual ela foi chamada.

Já com a função reversed(), obtem-se um iterador reverso da lista, que permite percorrê-la da posição do fim até a posição de início, sem alterar a ordem dos elementos na lista.

A função reversed() pode ser usada com tipos de sequência mutáveis e imutáveis (como tuple e str).

Veja como fica a solução do problema anterior usando essas duas funções:

In [13]:
#--------------------------------------------
# Programa principal
def main():
    print ("Lê n números reais e imprime-os em ordem reversa")
    n = int(input("Digite n: "))
    cont = 0
    seq = []  # cria uma lista vazia

    for i in range(n):
        num = float(input("Digite um número da sequência: "))
        seq.append(num)   # coloca num no final da lista

    print("Sequência original: ", seq)

    print("Solução 1: percorrendo a lista com o iterador reverso gerado por reversed()")

    for num in reversed(seq):
        print(num, end = ' ')

    print()
    print("Solução 2: usando a função reverse() para inverter os elementos na lista")
    seq.reverse()         # inverte a ordem dos elementos da lista

    print(seq)

#----------------------------------------------
main()
Lê n números reais e imprime-os em ordem reversa
Digite n: 5
Digite um número da sequência: 10
Digite um número da sequência: 20
Digite um número da sequência: 30
Digite um número da sequência: 40
Digite um número da sequência: 50
Sequência original:  [10.0, 20.0, 30.0, 40.0, 50.0]
Solução 1: percorrendo a lista com o iterador reverso gerado por reversed()
50.0 40.0 30.0 20.0 10.0 
Solução 2: usando a função reverse() para inverter os elementos na lista
[50.0, 40.0, 30.0, 20.0, 10.0]

Problema

Dadas n notas de provas, calcular a sua média e o número de notas acima da média calculada.

Solução

In [14]:
def main():
    '''
    Programa que le n notas de provas, calcula a media
    das notas da prova e imprime o numero de notas
    maiores que a media calculada.
    '''

    # leia o numero de notas
    n = int(input("Digite o número de notas: "))

    # inicializacoes
    soma_notas = 0
    lista_notas = []

    # calcule a soma das notas e crie uma lista com
    # as notas
    for i in range(n):
        nota = float(input("Digite uma nota: "))
        soma_notas += nota
        lista_notas.append(nota)

    # calcule a media
    media_notas = soma_notas/n
    print("A media das notas e %.1f" %(media_notas))

    # conte quantas notas estao acima da media
    cont = 0
    for nota in lista_notas:
        if nota > media_notas:
            cont += 1

    print("%d notas sao maiores que %.1f" %(cont, media_notas))

#----------------------------------------------------
main()
Digite o número de notas: 4
Digite uma nota: 6.3
Digite uma nota: 2.5
Digite uma nota: 9.8
Digite uma nota: 4
A media das notas e 5.7
2 notas sao maiores que 5.7

Problema

Dados n > 0 lançamentos de uma roleta (números entre 0 e 36), calcular a frequência de cada número.

Solução

In [15]:
#--------------------------------------------
# Programa principal
def main():
    print ("Frequência relativa de n lançamentos de uma roleta")
    n = int(input("Digite n: "))
    cont = 0
    seq = [0] * 37   # cria uma lista de 37 posições com zeros

    while cont < n:
        cont += 1
        num  = int(input("Digite o resultado do lançamento %d: "%(cont)))
        seq[num] += 1

    i = 0
    for freq in seq:
        if freq > 0:
            print("frequência dos números sorteados %d = %5.2f" %(i, freq/n))
        i += 1

    # ou ainda, usando as funções range() e len()
    print("Outra solução")
    for i in range(len(seq)):
        if seq[i] > 0:
            print ("frequência dos números sorteados %d = %5.2f" %(i, seq[i]/n))

#--------------------------------------------
main()
Frequência relativa de n lançamentos de uma roleta
Digite n: 8
Digite o resultado do lançamento 1: 12
Digite o resultado do lançamento 2: 31
Digite o resultado do lançamento 3: 7
Digite o resultado do lançamento 4: 31
Digite o resultado do lançamento 5: 9
Digite o resultado do lançamento 6: 12
Digite o resultado do lançamento 7: 12
Digite o resultado do lançamento 8: 5
frequência dos números sorteados 5 =  0.12
frequência dos números sorteados 7 =  0.12
frequência dos números sorteados 9 =  0.12
frequência dos números sorteados 12 =  0.38
frequência dos números sorteados 31 =  0.25
Outra solução
frequência dos números sorteados 5 =  0.12
frequência dos números sorteados 7 =  0.12
frequência dos números sorteados 9 =  0.12
frequência dos números sorteados 12 =  0.38
frequência dos números sorteados 31 =  0.25

Copiando listas

Quando fazemos uma de atribuição de uma variável do tipo list para uma outra variável, precisamos ter cuidado. A operação de atribuição nesse caso não faz uma cópia da lista na nova variável, ela apenas cria uma outra referência para a mesma lista. Veja o exemplo a seguir:

In [16]:
lista1 = [20, 40, 30, 10]
print("Lista 1:", lista1)
lista2 = lista1
print("Lista 2:", lista2)
print("Atribuindo um novo valor à primeira posição da Lista 1...")
lista1[0] = 50       # modifica primeira posição de lista1
print("Lista 1:", lista1)
print("Lista 2:", lista2)
print("Inclindo um novo elemento na Lista 2...")
lista2.append(60)
print("Lista 1:", lista1)
print("Lista 2:", lista2)
Lista 1: [20, 40, 30, 10]
Lista 2: [20, 40, 30, 10]
Atribuindo um novo valor à primeira posição da Lista 1...
Lista 1: [50, 40, 30, 10]
Lista 2: [50, 40, 30, 10]
Inclindo um novo elemento na Lista 2...
Lista 1: [50, 40, 30, 10, 60]
Lista 2: [50, 40, 30, 10, 60]

Pelo exemplo acima, é possível ver que uma modificação em lista1 é refletida também em lista2 e vice-versa. Na verdade, as variáveis lista1 e lista2 são apenas dois nomes diferentes para uma mesma lista.

Esse tipo de comportamento não acontece com variáveis dos tipos int e float. Veja o exemplo a seguir:

In [17]:
num1 = 20
num2 = num1
print(num1, num2)
num1 = 30
print(num1, num2)
num2 = 50
print(num1, num2)
20 20
30 20
30 50

Diante do exposto acima, qual é a forma correta de se copiar uma lista (ou seja, criar uma nova lista com os mesmos elementos de uma lista já existente)? A função clone() mostrada abaixo exemplifica uma forma de se fazer isso.

In [18]:
def clone(lista):
    """ (list) --> list
    
    Cria e retorna um clone da lista recebida como parâmetro.
    
    """
    clone = []
    for i in range(len(lista)):
        clone.append(lista[i])
        
    return clone


# Testa a função clone
lista3 = [0,1,2,3,4,5,6]
copia_lista3 = clone(lista3)   # cria uma cópia de lista3 na variável copia_lista3
print("Lista:", lista3)
print("Cópia da lista:", copia_lista3)
lista3[0] = 100
print("Lista modificada:", lista3)
print("Mas a cópia da lista não foi afetada:", copia_lista3)
Lista: [0, 1, 2, 3, 4, 5, 6]
Cópia da lista: [0, 1, 2, 3, 4, 5, 6]
Lista modificada: [100, 1, 2, 3, 4, 5, 6]
Mas a cópia da lista não foi afetada: [0, 1, 2, 3, 4, 5, 6]

Fatiamento de listas

Uma outra forma mais simples de criar uma cópia de uma lista é usando o operador o operador de "fatiar" listas :. Veja o exemplo a seguir:

In [19]:
lista3 = [0,1,2,3,4,5,6]
copia_lista3 = lista3[:]   # cria uma cópia de lista3 na variável copia_lista3
print("Lista:", lista3)
print("Cópia da lista:", copia_lista3)
lista3[0] = 100
print("Lista modificada:", lista3)
print("Mas a cópia da lista não foi afetada:", copia_lista3)
Lista: [0, 1, 2, 3, 4, 5, 6]
Cópia da lista: [0, 1, 2, 3, 4, 5, 6]
Lista modificada: [100, 1, 2, 3, 4, 5, 6]
Mas a cópia da lista não foi afetada: [0, 1, 2, 3, 4, 5, 6]

O exemplo acima mostra o operador : sendo usado em um caso particular, para criar uma cópia de uma lista. Mas, ele pode ser usado para criar uma nova lista a partir de qualquer "fatia" de elementos de uma outra lista. Veja alguns exemplos:

In [21]:
lista4 = [0,1,2,3,4,5,6]
lista5 = lista4[2:5]   # Cria uma nova lista contendo os elementos das pos. de 2 até a 4 (inclusive) da lista4  
lista6 = lista4[1:4]   # Cria uma nova lista contendo os elementos das pos. de 1 até a 2 (inclusive) da lista4  
print("L4:", lista4)
print("L5:", lista5)
print("L6:", lista6)
lista4[3] = 100
lista5[1] = 200
lista6[2] = 300
# Mostra que as modificações feitas em uma das listas não afetam as demais
print("L4:", lista4)
print("L5:", lista5)
print("L6:", lista6)
L4: [0, 1, 2, 3, 4, 5, 6]
L5: [2, 3, 4]
L6: [1, 2, 3]
L4: [0, 1, 2, 100, 4, 5, 6]
L5: [2, 200, 4]
L6: [1, 2, 300]

Quando fazemos lista[:], estamos usando o operador : para criar uma nova lista contendo a "fatia completa" de uma outra lista. Mas também podemos usar esse operador sem restringir apenas um dos limites, como nos exemplos abaixo:

In [22]:
lista7 = [0,1,2,3,4,5,6]
print(lista7[3:])   # imprime os elementos da lista a partir da posição 3
print(lista7[:5])   # imprime os elementos da lista até a posição 4
[3, 4, 5, 6]
[0, 1, 2, 3, 4]

No fatiamento, há ainda a possibilidade de especificar o tamanho do passo para avançar da posição de início até a posição de fim da fatia, como mostrado no exemplo abaixo:

In [23]:
lista8 = [0,1,2,3,4,5,6]
lista9 = lista8[1:6:2]
print(lista9)
[1, 3, 5]

Índice e verificação de pertinência de elementos em listas

no Python, é possível usar a função index() de um objeto do tipo list para obter o índice de um dado elemento dentro de uma lista. Também há o operador in, que verifica se um dado elemento está em uma lista. Alguns exemplos de uso do operador in e da função index() são mostrados abaixo:

In [24]:
lista = ["oi", 1, 3.14, "Maçã", 7, False]
print("'oi' in lista", "oi" in lista)
print("'oi' not in lista", "oi" not in lista)
print("not 'oi' in lista", not "oi" in lista)

if 5 in lista:
    print("5 está na lista")
else:
    print("5 não está na lista")

print("'Maçã' está na posicao %d da lista" %(lista.index("Maçã")))

if lista.index("oi") == 0:
    print("'oi' é o primeiro elemento da lista")
'oi' in lista True
'oi' not in lista False
not 'oi' in lista False
5 não está na lista
'Maçã' está na posicao 3 da lista
'oi' é o primeiro elemento da lista

Problema

Dada uma sequência de n números reais, escreva um programa que conte quantas vezes cada número ocorre na sequência.

Solução

In [25]:
def main():
    '''
    Dados n e uma sequência com n números reais,
    conta e imprime o numero de vezes que cada
    número ocorre na sequência.
    '''
    n = int(input("Digite o tamanho da sequência: "))

    lista_numeros = []
    cont_ocorrencias = []

    for i in range(n):
        numero = float(input("Digite um número: "))
        if numero not in lista_numeros:
            lista_numeros.append(numero)
            cont_ocorrencias.append(1)
        else:
            j = lista_numeros.index(numero)
            cont_ocorrencias[j] += 1

    print("    Número  no. ocorrências")
    for i in range(len(lista_numeros)):
        print("%10.2f      %6d" %(lista_numeros[i],cont_ocorrencias[i]))

#---------------------------------------------------
main()
Digite o tamanho da sequência: 5
Digite um número: 3
Digite um número: 2
Digite um número: 1
Digite um número: 2
Digite um número: 3
    Número  no. ocorrências
      3.00           2
      2.00           2
      1.00           1

Sobre o valor especial None

Python possui um valor especial, o None, que pode ser usado para representar a ausência de valor.

O None é útil, por exemplo, quando queremos indicar que uma dada posição de uma lista está vazia (ou seja, não possui um valor associada a ela). O tipo do valor None é NoneType; aliás, ele é o único valor existente desse tipo.

Veja os exemplos a seguir:

In [26]:
valor = None
print(valor, "-->", type(valor))
lista = [1,2,3,None,5,None]
print(lista," --> tamanho da lista:",len(lista))
None --> <class 'NoneType'>
[1, 2, 3, None, 5, None]  --> tamanho da lista: 6

Importante: Não confundir o valor especial None com as strings "None" ou "none". O valor especial é escrito sem aspas e com a primeira letra em maiúsculo.

In [27]:
valor1 = "None"   # Essa é uma string, não é o valor especial None
print("Tipo do valor 1:", type(valor1))
valor2 = None     # Esse é o valor especial None
print("Tipo do valor 2:", type(valor2))
valor1 == valor
Tipo do valor 1: <class 'str'>
Tipo do valor 2: <class 'NoneType'>
Out[27]:
False

Não podemos fazer operações matemáticas envolvendo o None como operador (ele não é equivalente ao valor zero!). Veja a seguir um exemplo de erro gerado quando tentamos fazer operações matemáticas com o None:

In [28]:
valor1 = 12
valor2 = None
valor1 + valor2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-28-2423c9d066cd> in <module>
      1 valor1 = 12
      2 valor2 = None
----> 3 valor1 + valor2

TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'

Quando precisamos fazer operações matemáticas envolvendo os elementos de uma lista que pode conter posições com o valor None, então é sempre preciso verificar o valor antes de envolvê-lo em algum cálculo, como mostrado no exemplo a seguir:

In [29]:
lista = [1,2,3,None,5,None]
# vamos fazer um laço para somar os elementos da lista
soma = 0
for elemento in lista:
    if elemento != None:  # só soma o elemento se ele não for None
        soma += elemento
print(soma)
11

Operações para Sequências

Vimos nesta aula várias exemplos de operações em listas, mas que na verdade se aplicam a outros tipos de sequências (como tuple, str e bytes). A tabela a seguir apresenta um resumo dessas e de outras operações para sequências:

Operação Descrição Observações
x in s True se existe em s um elemento igual a x, False no caso contrário
x not in s False se existe em s um elemento igual a x, True no caso contrário
s + t A concatenação de s e t
s * n ou n * s Equivale a adicionar s a ela mesma n vezes
s[i] i-ésimo elemento de s Início na posição 0 (1)
s[i:j] Fatia de s da posição i até j (1)(2)
s[i:j:k] Fatia de s da posição i até j com passo k (1)(2)
len(s) comprimento de s
min(s) menor elemento de s
max(s) maior elemento de s
s.index(x[, i[, j]]) índice da primeira ocorrência de x em s (na posição i ou depois dela e antes da posição j
s.count(x) número total de ocorrências de x em s

(1) Se i ou j é negativo, o índice é relativo ao fim da sequência.

(2) A fatia de s de i a j é definida como a sequência de itens com índice k tal que i <= k < j. Se i ou j é maior que len(s), considera len(s) no lugar. Se i é omitido ou None, usa 0. Se j é omitido ou None, usa len(s). Se i>= j, a fatia é vazia.

https://docs.python.org/3/library/stdtypes.html#typesseq

Operações para Sequências Mutáveis

Também vimos nesta aula alguns exemplos de operações de modificação em listas, mas que também podem ser aplicadas a qualquer tipo de sequência mutável (como é o caso de str e bytes). A tabela a seguir apresenta um resumo dessas e de outras operações de modificação para sequências mutáveis:

Operação Descrição Observações
s[i] = x Substitui elemento na i-ésima posição por x
s[i:j] = t Substitui a fatia s a i pelo conteúdo do iterável t
del s[i:j] Equivale a s[i:j] = []
s[i:j:k] = t Substitui os elementos de s[i:j:k] pelos de t t e s[i:j:k] precisam ter o mesmo tamanho
del s[i:j:k] Remove da sequência s os elementos em s[i:j:k]
s.append(x) Adiciona x no final da sequência
s.clear() Remove todos os elementos da sequência s
s.copy() Cria uma cópia (rasa) de s (como o s[:])
s.extend(t) ou s += t Extende s com o conteúdo de t
s *= n Atualiza s com o seu conteúdo repetido n vezes
s.insert(i, x) Insere x na posição i
s.pop([i]) Devolve o elemento na posição i e também o remove de s Valor default de i é -1
s.remove(x) Remove o primeiro elemento de s igual a x
s.reverse() Reverte os elementos de s, mudando a sequência original

https://docs.python.org/3/library/stdtypes.html#typesseq-mutable

Strings (tipo str)

Para lidar com dados textuais em Python, usamos strings, que são objetos do tipo str. Strings são sequências imutáveis de code points Unicode.

Strings literais podem ser delimitadas de diferentes formas:

  • 'exemplo de string "contendo aspas dentro" '
  • "exemplo de string 'contendo apóstrofes dentro' "
  • '''exemplo de string com quebras de linha dentro'''
  • """exemplo de string

com quebras de linha dentro"""

Assim como fazemos com listas, nós podemos:

  • usar a função len() para saber qual é o tamanho de uma string

  • acessar uma posição específica de uma string usando o operador de indexação []

  • usar o operador de "fatiar" : para obter trechos de uma string

Em Python, não existe um tipo de dado separado para caracteres (como o tipo char, de C). A indexação de uma string não vazia produz uma string de tamanho um.

Veja os exemplos a seguir:

In [30]:
texto = "A minha matéria favorita é MAC2166"
print("Texto completo: %s" %(texto))
print("O texto possui %d caracteres" %len(texto))
print("O caracter na posição 3 do texto é:", texto[2], type(texto[2]))
print("O trecho de texto entre as posições 7 e 15 é:", texto[6:15])
Texto completo: A minha matéria favorita é MAC2166
O texto possui 34 caracteres
O caracter na posição 3 do texto é: m <class 'str'>
O trecho de texto entre as posições 7 e 15 é: a matéria

Embora possamos acessar o seu valor, não podemos modificar uma posição específica de uma string usando indexação. Strings em Python são imutáveis. Essa é uma diferença importante entre strings e listas. Veja o exemplo abaixo:

In [31]:
poeminha = "Betatinha quando dorme, espalha a rama pelo chão"
poeminha[1] = "a"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-31-e481f9f747a0> in <module>
      1 poeminha = "Betatinha quando dorme, espalha a rama pelo chão"
----> 2 poeminha[1] = "a"

TypeError: 'str' object does not support item assignment

Há diferentes formas de se converter valores numéricos em strings. A mais direta delas é por meio da função str(), como mostrado nos exemplos a seguir:

In [32]:
num_dois = 2
print(num_dois, "-->", type(num_dois))
str_dois = str(num_dois)   # converte o valor em num_dois para string e armazena-o em str_dois
print(str_dois, "-->", type(str_dois))
2 --> <class 'int'>
2 --> <class 'str'>
In [33]:
str_real = str(3.33333333333)
print(str_real, "-->", type(str_real))
3.33333333333 --> <class 'str'>

Uma outra forma de converter números em strings é por meio de strings de formatação, como as que frequentemente usamos nos comandos print e input, nos exercícios que fazemos em aula. Veja exemplos a seguir:

In [34]:
num_real1 = 13.2278430
num_real2 =  4.9
num_int1 = 121
num_int2 = 6
str_reais_formatados = "Números reais formatados: |%6.3f|, |%6.3f|" %(num_real1, num_real2)
print(str_reais_formatados)
str_ints_formatados = "Números inteiros formatados: |%4d|, |%4d|" %(num_int1, num_int2)
print(str_ints_formatados)
str_num_simples = "%d" %(num_int1)
print(str_num_simples, "-->", type(str_num_simples))
Números reais formatados: |13.228|, | 4.900|
Números inteiros formatados: | 121|, |   6|
121 --> <class 'str'>

Formatação de Strings

Há diferentes formas de se formatar strings em Python:

  1. Com o operador %d (ao estilo printf de C) - https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting
  2. Com o método format() - https://docs.python.org/3/library/stdtypes.html#str.format
  3. Com f-strings (formatted string literals) - introduzido no Python 3.6 - https://docs.python.org/3/reference/lexical_analysis.html#f-strings

Veja exemplos de seu uso abaixo:

In [36]:
nome = "Fulano de Tal"
peso = 87.352

str1 = "Usando o operador '%%d': %s, %3.1f" %(nome, peso)   
print(str1)

str2 = "Usando o método 'format()': {}, {:3.1f}".format(nome, peso)
print(str2)

str3 = f"Usando uma 'f-string': {nome} {peso:3.1f}"
print(str3)
Usando o operador '%d': Fulano de Tal, 87.4
Usando o método 'format()': Fulano de Tal, 87.4
Usando uma 'f-string': Fulano de Tal 87.4

O operador + (de concatenação) pode ser aplicado tanto a listas quanto a strings. O primeiro exemplo a seguir mostra um caso de uso envolvendo listas, enquanto o segundo exemplo se refere à concatenação de strings:

In [37]:
lista1 = [1,2,3]
lista2 = [9,8,7,6,5]
lista3 = lista1 + lista2 # cria uma nova lista contendo os elementos de lista1 e lista2
print(lista3)
[1, 2, 3, 9, 8, 7, 6, 5]
In [38]:
verso1 = "Como diria o Cebolinha: "
verso2 = "- Keep calm and make an infallible plan!"
citacao = verso1 + verso2  # cria uma nova string com a junção de verso1 e verso2
print(citacao)
Como diria o Cebolinha: - Keep calm and make an infallible plan!

As funções ord() e chr()

A função ord() devolve o código numérico do caractere passado como parâmetro. A função chr() devolve o caracter corresponde ao código numérico passado como parâmetro.

Veja os exemplos a seguir:

In [39]:
print(type("A"))
<class 'str'>
In [40]:
print(ord("8"))
print(ord("?"))
print(ord("A"))
print(ord("C"))
print(ord("^"))
print(ord("a"))
56
63
65
67
94
97

A função ord() gerará um erro se passarmos como parâmetro uma string contendo mais de um caracter:

In [41]:
ord("olá!")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-41-d1f258c13368> in <module>
----> 1 ord("olá!")

TypeError: ord() expected a character, but string of length 4 found
In [42]:
print(chr(43))
print(chr(54))
print(chr(65))
print(chr(472))
+
6
A
ǘ

Problema

Dada uma sequência de caracteres representando um texto, determinar a frequência relativa de vogais não acentuadas no texto.

Por exemplo, no texto:

"Em terra de cego quem tem um olho e caolho"

essa frequência é 16/42.

Solução 1 (usa for elemento in ...)

In [44]:
def main():
    texto = input("Digite um texto: ")

    n = len(texto)
    nv = 0
    vogais = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']

    for letra in texto:
        if letra in vogais:
            nv += 1

    print ("Frequencia relativa = %d/%d = %f" %(nv, n, nv/n))

#-------------------------------------------
main()
Digite um texto: Em terra de cego quem tem um olho e caolho
Frequencia relativa = 16/42 = 0.380952

Solução 2 (usa for para varrer a lista de vogais)

In [45]:
def main():
    texto = input("Digite um texto: ")

    n = len(texto)
    nv = 0
    vogais = "aeiouAEIOU"

    for i in range(n):
        for j in range(len(vogais)):
            if texto[i] == vogais[j]:
                nv += 1

    print ("Frequencia relativa = %d/%d = %f" %(nv, n, nv/n))

#-------------------------------------------
main()
Digite um texto: Em terra de cego quem tem um olho e caolho
Frequencia relativa = 16/42 = 0.380952

Funções para Strings

O tipo string em Python possui funções para converter uma string para letras maiúsculas ou minúsculas - são as funções upper() e lower(). Veja um exemplo do uso delas a seguir:

In [46]:
texto = "PeQuEno TesTE"
textoMaiusculo = texto.upper()  # cria uma string com o texto em letras maiúsculas
textoMinusculo = texto.lower()  # cria uma string com o texto em letras minúsculas
print(textoMaiusculo)
print(textoMinusculo)
PEQUENO TESTE
pequeno teste

A função split() de str cria uma lista de strings a partir de uma só string. A função recebe como parâmetro o caractere (ou a string) que será usada como separador de substrings dentro da string a ser "desmembrada". Veja os exemplos de uso dela a seguir:

In [47]:
texto = "Passarim quis pousar, não deu, voou"
palavras = texto.split(" ")   # usa o caracter de espaço como separador de substrings   
print(palavras)
['Passarim', 'quis', 'pousar,', 'não', 'deu,', 'voou']
In [48]:
outro_texto = "Este é um string"
pedacos = outro_texto.split("t")  # usa "t" como caracter separador
print(pedacos) 
['Es', 'e é um s', 'ring']

Outros exemplos de operações de Python específicas para strings bastante usadas são:

  • str.find(sub[, start[, end]]) - devolve o menor índice no qual a string sub é encontrada na fatia s[start:end]
  • str.join(iterable) - devolve uma nova string com a concatenação das strings em iterable
  • str.replace(old, new[, count]) - devolve uma nova string em que todas as count primeiras ocorrências da string old são substituídas por new
  • str.strip([chars]) - devolve uma nova string sem os caracteres em chars no início ou no fim da string (o default é remover espaços em branco)

Para a descrição dessas e das demais funções para strings, consulte: https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str

List Comprehensions (listcomps)

List comprehensions (ou listcomps, como são chamadas pelos pythonistas) são uma forma prática e elegante de se construir uma lista com base em uma outra sequência. Com elas, pode-se facilmente criar, por exemplo, uma lista nova a partir da aplicação de uma função a cada um dos elementos da sequência de origem ou da filtragem de seus elementos.

O formato geral de uma listcomp é (a parte do if é opcional):

<nova_lista> = [<expressão> for <item> in <iterável> if <condição> == True]

Veja exemplos de uso de listcomps abaixo:

In [49]:
import math

lista1 = [49, 25, 64, 2]
print("Lista 1:", lista1)

# Gera nova lista com a raiz quadrada dos números da lista original
lista2 = [math.sqrt(num) for num in lista1]
print("Lista 2:", lista2)

# Exibe a lista 1 de novo, para mostrar que ela não 
# foi alterada com o listcomp
print("Lista 1 de novo:", lista1)

# Gera lista com as palavras de uma string
lista3 = [palavra for palavra in "Batatinha quando nasce".split()]
print("Lista 3", lista3)
Lista 1: [49, 25, 64, 2]
Lista 2: [7.0, 5.0, 8.0, 1.4142135623730951]
Lista 1 de novo: [49, 25, 64, 2]
Lista 3 ['Batatinha', 'quando', 'nasce']

Como pode ser visto na lista2 do exemplo acima, as listcomps podem gerar listas com elementos de tipos de dados diferentes dos da lista original.

Veja abaixo o código de criação das mesmas listas do exemplo anterior, mas desta vez usando apenas laços, sem usar listcomps. Observe que, com os listcomps, não é preciso criar a lista vazia e nem usar o append para incluir os elementos.

In [50]:
import math

lista1 = [49, 25, 64, 2]
print("Lista 1:", lista1)

# Gera nova lista com a raiz quadrada dos números da lista original
lista2 = [] 
for num in lista1:
    lista2.append(math.sqrt(num))
    
print("Lista 2:", lista2)

# Exibe a lista 1 de novo, para mostrar que ela não 
# foi alterada com os listcomps                    
print("Lista 1 de novo:", lista1)

# Gera lista com as palavras de uma string
lista3 = [] 
for palavra in "Batatinha quando nasce".split():
    lista3.append(palavra)
    
print("Lista 3:", lista3)
Lista 1: [49, 25, 64, 2]
Lista 2: [7.0, 5.0, 8.0, 1.4142135623730951]
Lista 1 de novo: [49, 25, 64, 2]
Lista 3: ['Batatinha', 'quando', 'nasce']

Obs.: Toda listcomp pode ser reescrita na forma de laço, mas nem todo laço pode ser reescrito como uma listcomp.

Também é possível usar em listcomps condicionais (if), tanto na <expressão> quanto dentro do laço for (para filtrar elementos). Veja os exemplos abaixo:

In [51]:
lista1 = [10, 15, 20, 25, 30, 35]
print("Lista 1:", lista1)

# Gera nova lista somente com o quadrado dos números pares
# da lista original
lista2 = [num**2 for num in lista1 if num % 2 == 0]    
print("Lista 2:", lista2)

# Gera nova lista somente com os números da lista
# original que são pares e múltiplos de 3 
lista3 = [num for num in lista1 if num % 2 == 0 if num % 3 == 0]    
print("Lista 3:", lista3)

# Gera uma lista de strings que indicam se os números na lista 
# original são pares ou ímpares
lista4 = ["Par" if num % 2 == 0 else "Ímpar" for num in lista1]    
print("Lista 4:", lista4)
Lista 1: [10, 15, 20, 25, 30, 35]
Lista 2: [100, 400, 900]
Lista 3: [30]
Lista 4: ['Par', 'Ímpar', 'Par', 'Ímpar', 'Par', 'Ímpar']

A implementação equivalente dos exemplos acima sem usar listcomps é mostrada abaixo:

In [52]:
lista1 = [10, 15, 20, 25, 30, 35]
print("Lista 1:", lista1)

# Gera nova lista somente com o quadrado dos números pares
# da lista original
lista2 = []
for num in lista1:
    if num % 2 == 0:    
        lista2.append(num**2)

print("Lista 2:", lista2)

# Gera nova lista somente com os números da lista
# original que são pares e múltiplos de 3 
lista3 = [] 
for num in lista1:
    if num % 2 == 0: 
        if num % 3 == 0:
            lista3.append(num)

print("Lista 3:", lista3)

# Gera uma lista de strings que indicam se os números na lista 
# original são pares ou ímpares
lista4 = []
for num in lista1:
    if num % 2 == 0:
        lista4.append("Par")
    else:
        lista4.append("Ímpar")
        
print("Lista 4:", lista4)
        
Lista 1: [10, 15, 20, 25, 30, 35]
Lista 2: [100, 400, 900]
Lista 3: [30]
Lista 4: ['Par', 'Ímpar', 'Par', 'Ímpar', 'Par', 'Ímpar']

Também é possível ter em listcomps laços aninhados, o que possibilita, por exemplo, gerar o produto cartesiano de duas ou mais listas:

In [53]:
cores = ["Verde", "Amarelo", "Azul", "Branco"]
tamanhos = ["P", "M", "G"]
camisetas = [[tam,cor] for tam in tamanhos for cor in cores]
print(camisetas)
[['P', 'Verde'], ['P', 'Amarelo'], ['P', 'Azul'], ['P', 'Branco'], ['M', 'Verde'], ['M', 'Amarelo'], ['M', 'Azul'], ['M', 'Branco'], ['G', 'Verde'], ['G', 'Amarelo'], ['G', 'Azul'], ['G', 'Branco']]

Referências:

  1. Videoaulas de Introdução à Ciência da Computação com Python, do prof. Fabio Kon: https://www.youtube.com/playlist?list=PLcoJJSvnDgcKpOi_UeneTNTIVOigRQwcn
  2. Notas de aula para cursos de Introdução à Computação em Python do IME-USP: https://panda.ime.usp.br/cc110/static/cc110/index.html
  3. Livro: Como Pensar Como um Cientista da Computação - Aprendendo com Python: Versão Interativa https://panda.ime.usp.br/pensepy/static/pensepy/index.html
  4. Notas de aula da disciplina MAC2166: https://www.ime.usp.br/~mac2166/1s20/index.html
  5. Livro Fluent Python: Clear, Concise, and Effective Programming: https://www.oreilly.com/library/view/fluent-python-2nd/9781492056348/
In [ ]: