List Comprehensions


In [1]:
minhalista = "Como fazer uma list comprehension".split()

Observe que na linha acima aplicamos o método split diretamente a uma string, sem precisarmos nomear uma variável com o conteúdo da string!


In [2]:
minhalista


Out[2]:
['Como', 'fazer', 'uma', 'list', 'comprehension']

Como transformar todas as primeiras letras de cada item da lista em maiúsculas?


In [3]:
minhalista = [x.capitalize() for x in minhalista]

In [4]:
minhalista


Out[4]:
['Como', 'Fazer', 'Uma', 'List', 'Comprehension']

Observe que x é uma variável local à list comprehension; ela serve apenas para que possamos fazer referência a cada item da lista sendo percorrida na nova expressão que queremos gerar. Fora da list comprehension, o Python não sabe quem é esse x:


In [6]:
x


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-6-401b30e3b8b5> in <module>()
----> 1 x

NameError: name 'x' is not defined

Exemplo: língua do P


In [7]:
linguadope = ["Pe"+palavra for palavra in minhalista]

In [8]:
linguadope


Out[8]:
['PeComo', 'PeFazer', 'PeUma', 'PeList', 'PeComprehension']

Para transformarmos essa lista em uma string, podemos usar o método join:


In [9]:
" ".join(linguadope)


Out[9]:
'PeComo PeFazer PeUma PeList PeComprehension'

Uma explicação para a sintaxe do join: http://www.faqs.org/docs/diveintopython/odbchelper_join.html (basicamente, o método join precisa de duas strings: um resultado e uma "cola". Mas o argumento a ser unido pode ser outra coisa além de uma string (notadamente, iterables)

Exemplo: lista de números

É comum querermos gerar uma lista de números delimitada por dois valores. A função range(a,b) gera uma lista que vai do número a até b-1; porém, o resultado da função range não é a lista diretamente, mas uma estrutura de dados que precisamos transformar em uma lista.


In [15]:
numeros = [n for n in range(0,10)]
print(numeros)


[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Podemos, usando list comprehensions, gerar outras listas. Por exemplo, gerar uma lista de números ímpares:


In [16]:
numeros = [2*n+1 for n in range(0,11)]

In [17]:
numeros


Out[17]:
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21]

Slicing

Podemos selecionar pedaços de uma lista (ou string) facilmente usando o conceito de slicing.


In [18]:
numeros[0]


Out[18]:
1

In [19]:
numeros[-1]


Out[19]:
21

In [20]:
numeros[3:4]


Out[20]:
[7]

Observe que, com um parâmetro a mais, podemos selecionar os elementos da lista de 2 em 2:


In [21]:
numeros[0:11:2]


Out[21]:
[1, 5, 9, 13, 17, 21]

Também podemos calcular o tamanho de uma lista de números:


In [22]:
len(numeros)


Out[22]:
11

In [23]:
numeros[-3]


Out[23]:
17

Podemos gerar uma nova lista contendo pedaços da lista original:


In [24]:
numeros = [numeros[4:6],numeros[3:8]]
print(numeros)


[[9, 11], [7, 9, 11, 13, 15]]

Infelizmente, o resultado acima é uma lista de listas: cada elemento da lista é, por sua vez, uma outra lista:


In [25]:
numeros[0]


Out[25]:
[9, 11]

Assim, para acessarmos um elemento individual da lista numeros, precisamos utilizar um índice para a lista externa, e outro índice para a lista interna:


In [26]:
numeros[0][1]


Out[26]:
11

Para transformarmos aquela lista de listas em uma lista simples, podemos usar o comando abaixo (admito que é um pouco mágico, mas funciona! ;))


In [27]:
lista = [item for sublist in numeros for item in sublist]
lista


Out[27]:
[9, 11, 7, 9, 11, 13, 15]

Observe que o slicing também vale para sequências de caracteres (strings):


In [28]:
palavra = "teste"

In [29]:
palavra[1:]


Out[29]:
'este'

Comandos de repetição e condicionais

Repetição: for

Às vezes, desejamos repetir um certo número de vezes a mesma operação.

De fato, uma lista comprehension inclui um comando de repetição: executamos alguma ação com cada item de uma lista; se lermos a expressão da lista comprehension, poderíamos dizer: "retorne n para cada n no conjunto que vai de 0 a 10":


In [32]:
numeros = [n for n in range(0,11)]
print(numeros)


[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Fazemos isso explicitamente quando usamos a estrutura for. Observe que, no Python, não precisamos sinalizar o fim de um bloco de código; na verdade, a indentação sinaliza um bloco. Observe a diferença entre as células abaixo:


In [35]:
for item in numeros: # Indentação
    print("Numero "+str(item))
print("bla")


Numero 0
Numero 1
Numero 2
Numero 3
Numero 4
Numero 5
Numero 6
Numero 7
Numero 8
Numero 9
Numero 10
bla

In [36]:
for item in numeros: # Indentação
    print("Numero "+str(item))
    print("bla")


Numero 0
bla
Numero 1
bla
Numero 2
bla
Numero 3
bla
Numero 4
bla
Numero 5
bla
Numero 6
bla
Numero 7
bla
Numero 8
bla
Numero 9
bla
Numero 10
bla

Condicionais: if

Agora, se desejamos realizar uma operação caso alguma condição seja satisfeita, e outra caso contrário, usamos a estrutura if: "se determinada condição lógica for verdadeira, execute o primeiro bloco de comandos; caso contrário (else), execute o segundo".


In [37]:
palavra = "bla"
if palavra == "bla!":
    print("Verdadeiro")
else:
    print("Falso")


Falso

Usamos == na expressão acima, pois no Python é necessário diferenciar entre um comando de atribuição (atribuir um valor a uma variável) e um comando de comparação (testar se duas variáveis são iguais). O caso do if é o segundo.

Podemos também acrescentar outras condições lógicas ao nosso teste.


In [38]:
if palavra == "bla!" and 3 > 2:
    print("Aha")
else:
    print("Uhu")


Uhu

In [47]:
if palavra == "bla!" or 3>2:
    print("Aha")
else:
    print("Uhu")


Aha

Scripting

Exemplo 1

Percorrer um diretório com diversos arquivos e procurar todos os arquivos que satisfazem algum critério, realizando alguma operação nesses arquivos.

Para acessarmos comandos e operações realizadas no nível do sistema operacional, utilizamos o módulo os.


In [2]:
import os

Atenção: Escolha um diretório no seu computador para executar esse exemplo, com arquivos que possam ser renomeados.

No meu caso, usarei os arquivos do diretório oceanobiopython/exemplos/exemplo_1


In [24]:
diretorio = os.path.join(os.getcwd(), "..","exemplos/exemplo_1")

Em seguida, vamos listar todos os arquivos deste diretório.


In [10]:
os.listdir(diretorio)


Out[10]:
['meme.png', 'qualquercoisa.gif', 'file.txt', 'outro.pdf', 'arquivo.txt']

Para que possamos percorrer a lista que contém os nomes de todos os arquivos deste diretório, vamos salvar esta lista de nomes de arquivo:


In [11]:
lista = os.listdir(diretorio)

Agora, vamos efetuar a seguinte operação: todos os arquivos deste diretório que tiverem a extensão ".txt" terão um novo nome iniciando com letra maiúscula.


In [12]:
for arquivo in lista:
    if arquivo[-3:] == "txt":
        os.rename(os.path.join(diretorio,arquivo),os.path.join(diretorio,arquivo.capitalize()))

Verificando que funcionou:


In [13]:
os.listdir(diretorio)


Out[13]:
['meme.png', 'qualquercoisa.gif', 'File.txt', 'outro.pdf', 'Arquivo.txt']

(é claro que se você estiver em um diretório em que não hajam arquivos com extensão ".txt", nada irá acontecer!)

Para desfazermos este exemplo, podemos executar o seguinte script:


In [15]:
lista = os.listdir(diretorio)
for arquivo in lista:
    os.rename(os.path.join(diretorio,arquivo),os.path.join(diretorio,arquivo.lower()))

In [16]:
os.listdir(diretorio)


Out[16]:
['meme.png', 'qualquercoisa.gif', 'file.txt', 'outro.pdf', 'arquivo.txt']

Exemplo 2

Organizar os arquivos de um diretório pela data da última modificação.


In [17]:
import os
diretorio = os.path.join(os.getcwd(), "..","exemplos/exemplo_2")
print(diretorio)
print(os.listdir(diretorio))


/home/melissa/Dropbox/trabalho/2016.2/oceanobiopython/Notebooks/../exemplos/exemplo_2
['file5.txt', 'file2.txt', 'file1.txt', 'teste.txt', 'file4.txt', 'file3.txt']

Agora, para descobrirmos quando o arquivo foi modificado pela última vez, precisamos usar uma função que não retorna a data da última modificação no formato em que estamos acostumados. Ela retorna o tempo, em segundos, decorrido desde 1o de janeiro de 1970 (se você estiver no Unix). Para podermos obter o que queremos, usamos então a função ctime do módulo time.


In [18]:
import time
print(os.path.getmtime(os.path.join(diretorio,"file1.txt")))
time.ctime(os.path.getmtime(os.path.join(diretorio,"file1.txt")))


1473628286.1679237
Out[18]:
'Sun Sep 11 18:11:26 2016'

In [19]:
lista = os.listdir(diretorio)
for arquivo in lista:
    print(time.ctime(os.path.getmtime(os.path.join(diretorio,arquivo))))


Thu Sep  8 22:42:51 2016
Wed Sep  7 11:00:22 2016
Sun Sep 11 18:11:26 2016
Wed Sep 14 22:38:26 2016
Mon Aug 29 13:19:03 2016
Tue Aug 16 08:24:00 2016

In [20]:
os.mkdir(os.path.join(diretorio,"arquivos_setembro"))
os.mkdir(os.path.join(diretorio,"arquivos_agosto"))

In [21]:
for arquivo in lista:
    if arquivo != "teste.txt":
        data_modificacao = time.ctime(os.path.getmtime(os.path.join(diretorio,arquivo)))
        if data_modificacao[4:7] == "Sep":
            os.rename(os.path.join(diretorio,arquivo), os.path.join(diretorio,"arquivos_setembro",arquivo))
        elif data_modificacao[4:7] == "Aug":
            os.rename(os.path.join(diretorio,arquivo), os.path.join(diretorio,"arquivos_agosto",arquivo))

Agora, vamos desfazer o exercício para restaurarmos o diretório à estrutura original:


In [22]:
lista = os.listdir(diretorio)
for item in lista:
    if os.path.isdir(os.path.join(diretorio,item)):
        locais = os.listdir(os.path.join(diretorio,item))
        print(locais)
        for arquivo in locais:
            os.rename(os.path.join(diretorio,item,arquivo),os.path.join(diretorio,arquivo))
        os.rmdir(os.path.join(diretorio,item))


['file5.txt', 'file2.txt', 'file1.txt']
['file4.txt', 'file3.txt']

In [23]:
print(os.listdir(diretorio))


['file5.txt', 'file2.txt', 'file1.txt', 'teste.txt', 'file4.txt', 'file3.txt']

(Fim da Aula 2, ministrada em 15/09/2016)