Tradução e modificação do material associado a programmingforbiology.org, associado a disciplina "CEN0336 - Introdução a Programação de Computadores Aplicada a Ciências Biológicas"
Criador e Instrutor da versão em Português Diego M. Riaño-Pachón
Criadores do material na versão em Inglês Simon Prochnik Sofia Robb
Python é uma linguagem de script. Ela é útil para desenvolvimento de projetos científicos de médio porte. Quando você executa um script de Python, o interpretador da linguagem irá gerar um código em bytes e interpretá-lo. Esse processo acontece automaticamente, você não precisa se preocupar com isso. Linguagens compiladas como C e C++ vão rodar muito mais rapidamente, mas são também muito mais complicadas de programar. Programas usando linguagens como Java (que também são compiladas) são adequados para projetos grandes com programação colaborativa, mas não são executados tão rapidamente como C e são mais complexos de escrever que Python.
Python tem:
- tipos de dados
- funções
- objetos
- classes
- métodos
Tipos de dados correspondem aos diferentes tipos de dados que serão discutidos em mais detalhes posteriormente. Exemplos de tipos de dados incluem números inteiros e cadeias de caracteres (texto). Eles podem ser armazenados em variáveis.
Funções fazem algo com dados, como cálculos. Algumas funções estão disponíveis de forma nativa em Python. Você pode também criar suas próprias funções.
Objetos correspondem a maneiras de agrupar conjuntos de dados e funções (métodos) que agem nestes dados.
Classes correspondem a uma maneira de encapsular (organizar) variáveis e funções. Objetos usam variáveis e métodos da classe às quais pertencem.
Métodos são funções que pertencem a uma classe. Objetos que pertencem a uma classe podem usar métodos daquela classe.
Há duas versões de Python: Python 2 e Python 3. Nós usaremos Python 3. Esta versão conserta problemas de Python 2 e é incompatível em alguns aspectos com Python 2. Muitos códigos já foram desenvolvidos em Python 2 (é uma versão mais antiga), mas muitos códigos já foram e estão sendo desenvolvidos em Python 3.
Python pode ser executado em uma linha por vez em um interpretador interativo. É como se usasse a linha de comando de Shell (que estudamos nas duas primeiras aulas/capítulos), mas agora com a linguagem Python. Para executar o interpretador, execute o seguinte código no seu terminal:
$ python3
Nota: '$' indica o prompt de comando. Lembre-se do Unix 1 que cada computador tem seu próprio prompt!
Primeiros comandos em Python:
>>> print("Olá, turma 2024!")
Olá, turma 2024!
Nota:
print()
- O mesmo código acima é digitado em um arquivo usando um editor de texto.
- Scripts em Python são sempre salvos em arquivos cujos nomes têm a extensão '.py' (o nome do arquivo termina com '.py').
- Poderíamos executar o código
ola.py
Conteúdos do arquivo:
print("Olá, turma 2024!")
Digitar o comando python3
seguido do nome do script faz com que Python execute o código. Lembre-se que nós vimos que podemos também executar o código de forma interativa executando apenas python3
(ou python
) na linha de comando.
Execute o script desta forma (% representa o prompt):
% python3 ola.py
Este procedimento gera o seguinte resultado no terminal:
Olá, turma 2024!
Se você tornar script em um executável, você pode executá-lo sem precisar digitar python3
antes. Use o comando chmod
para alterar as permissões do script desta forma:
chmod +x ola.py
Você pode verificar as permissões assim:
% ls -l ola.py
-rwxr-xr-x 1 sprochnik staff 60 Oct 16 14:29 ola.py
Os primeiros 10 caracteres que aparecerem na tela possuem significados especiais. O primeiro (-
) diz a você qual tipo de arquivo ola.py
é. -
significa um arquivo normal, 'd' um diretório, '1' um link. Os próximos nove caracteres aparecem em três sets de três. O primeiro set se refere às suas permissões, o segundo às permissões do grupo, e o último de quaisquer outros. Cada set de três caracteres mostra em ordem 'rwx' para leitura, escrita, execução. Se alguém não tem uma permissão, um -
é mostrado ao invés de uma letra. Os três caracteres 'x' significam que qualquer um pode executar ou rodar o script.
Nós também precisamos adicionar uma linha no começo do script que pede para o python3 interpretar o script. Essa linha começa com #
, então aparece como um comentário para o python. O '!' é importante como o espaço entre env
e python3
. O programa /usr/bin/env
procura por onde python3
está instalado e roda o script com python3
. Os detalhes podem parecer um pouco complexos, mas você pode apenas copiar e colar essa linha 'mágica'.
Esse arquivo ola.py agora se parece com isso
#!/usr/bin/env python3
print("Olá, turma 2024!")
Agora você pode simplesmente digitar o símbolo para o diretório atual .
seguido por um /
e o nome do script para rodá-lo. Como isso:
% ./ola.py
Olá, turma 2024!
Um nome de variável em Python é o nome usado para identificar uma variável, função, classe, módulo ou outro objeto. Um nome de variável inicia com uma letra, de A
a Z
ou de a
a z
, ou então com um travessão (_
), seguido de zero ou mais letras, travessões e dígitos (0
a 9
).
Python não permite caracteres como @
, $
e %
dentro do nome de variável. Python é uma linguagem "sensível a minúsculas e maiúsculas" (muitas vezes referido com o anglicismo "case sentitive"). Portanto, seq_id
e seq_ID
são dois nomes diferentes de variável em Python.
- A primeira letra deve ser minúscula, exceto em nomes de classes. Classes devem começar com letra maiúscula (p.e.
Seq
). - Os nomes de variáveis privadas são iniciadas com sublinhado (ex.
_private
). - Os nomes de variáveis privadas fortes (verdadeiras) são iniciadas com dois sublinhados (ex.
__private
). - Nomes especiais de variáveis definidas pela linguagem começam e terminam com dois travessões (p.e.
__special__
).
Selecionar bons nomes de variáveis para objetos que você nomeia é muito importante. Não chame suas variáveis de item
ou minha_lista
ou dados
ou var
, exceto em casos que você esteja trabalhando com trechos de códigos muito simples (a título de testes) ou fazendo algum gráfico. Não dê x
ou y
como nome de variáveis. Todos estes nomes não são descritivos para o tipo de informação encontrado naquela variável ou objeto.
Uma escolha ainda pior é dar nomes de variáveis que contêm nomes de genes como sequencias
. Por que é uma ideia ruim? Pense no que poderia acontecer se você encher seu carro de combustível em um comércio chamado "posto de gasolina" que vendesse limonada em vez de gasolina ou etanol combustível.
Em Ciência da Computação, os nomes devem sempre descrever de forma acurada os objetos aos quais estejam vinculados. Isso reduz a possibilidade de bugs
no seu código, torna muito mais fácil o seu entendimento se você volta ao seis meses depois ou por pessoas com as quais compartilha seu código. Embora pensar em bons nomes para variáveis tome um pouco mais de tempo e esforço, isso previne problemas no futuro!
A lista a seguir compreende as palavras reservadas de Python. Elas são palavras especiais que já têm um propósito em Python e, portanto, não podem ser usadas como nomes de variáveis.
and exec not
as finally or
assert for pass
break from print
class global raise
continue if return
def import try
del in while
elif is with
else lambda yield
except list hash
Python considera como um bloco de código linhas adjacentes que apresentam o mesmo nível de indentação. Isso mantém organizadas as linhas de código que são executadas de forma conjunta. Espaçamento e/ou indentação incorretos irão causar erros ou podem fazer com que seu código seja executado de uma forma que você não espera. Ambientes de Desenvolvimento Interativo (IDEs) e editores de texto podem ajudar a indentar códigos corretamente.
O número de espaços na indentação precisa ser consistente, mas este número não é específico. Todas as linhas de código ou sentenças dentro de um bloco precisam ser indentados com o mesmo número. Por exemplo, usando quatro espaços:
#!/usr/bin/env python3
mensagem = '' # cria uma variável vazia
for x in (1,2,3,4,5):
if x > 4:
print("Olá")
mensagem = 'x é grande'
else:
print(x)
mensagem = 'x é pequeno'
print(mensagem)
print('Pronto!')
Incluir comentários no seu código é uma prática essencial. Anotar o que uma linha ou bloco de código faz ajudará o programador e os leitores do código. Incluindo você!
Comentários iniciam com o símbolo #
. Todos os caracteres depois deste símbolo, até o final da linha, são parte do comentário e serão ignorados pelo interpretador de Python.
A primeira linha de um script começa com #!
, um exemplo especial de comentário que tem a função especial no Unix de informar ao Shell como executar o script.
#!/usr/bin/env python3
# este é meu primeiro código
print("Olá, turma 2024!") # esta linha imprime o conteúdo na tela
Linhas em branco são importantes para aumentar a legibilidade do código. Você deve separar com uma linha em branco trechos de código que vão juntos, organizando em "parágrafos" de código. Linhas em branco são ignoradas pelo interpretador de Python.
Esta é a sua primeira oportunidade de olhar para variáveis e tipos de dados. Cada tipo será discutido em mais detalhes nas seções subsequentes.
O primeiro conceito a ser considerado é que os tipos de dados de Python podem ser ou não mutáveis. Números literais, strings e tuplas não podem ser alterados. Listas, dicionários e sets podem. Da mesma forma, variáveis individuais também podem ser alteradas. Você pode armazenar dados na memória por meio da atribuição de variáveis, o que pode ser feito usando o sinal "=".
Números e strings são dois tipos comuns de dados. Números literais e strings como 5
ou meu nome é
são imutáveis. No entanto, seus valores podem ser armazenados em variáveis, as quais podem ser alteradas.
Por exemplo:
contagem_genes = 5
# alterando o valor de contagem_genes
contagem_genes = 10
Lembre-se da seção anterior sobre nomes de variáveis e objetos (e variáveis são objetos em Python).
Diferentes tipos de dados podem ser atribuídos a variáveis, como inteiros (1
,2
,3
), números de ponto flutuante (3.1415
) e strings ("texto"
).
Por exemplo:
contagem = 10 # este é um inteiro
média = 2.531 # este é um número de ponto flutuante
mensagem = "Bem-vindo ao interpretador de Python" # isso é uma string
10
, 2.531
e "Bem-vindo ao interpretador de Python"
são peças de dados singulares (escalares) e cada um é armazenado em sua própria variável.
Coleções de dados podem também ser armazenados em tipos de dados especiais, i.e., tuplas, listas, sets, e dicionários. Você deveria sempre tentar armazenar semelhantes com semelhantes, de forma tal que cada elemento da coleção deveria ser do mesmo tipo de dado, como um valor de expressão de RNA-seq ou uma contagem de quantos exons estão em um gene ou uma sequência de leitura. Para o quê você imagina que isso deve ser?
- Listas são usadas para armazenar coleções de dados ordenados (indexados).
- Listas são mutáveis: o número de elementos em uma lista e o que é armazenado em cada elemento podem ser alterados.
- Listas são delimitadas por colchetes e seus itens separados por vírgula.
[ 'atg' , 'aaa' , 'agg' ]
Índice | Valor |
---|---|
0 | atg |
1 | aaa |
2 | agg |
A indexação de listas começa em 0
- Tuplas são similares a listas e contêm coleções de dados ordenados (indexados).
- Tuplas são imutáveis: você não consegue alterar os valores ou número de elementos
- A tupla é delimitada por parênteses e seus itens são separados por vírgula.
( 'Jan' , 'Fev' , 'Mar' , 'Abr' , 'Mai' , 'Jun' , 'Jul' , 'Ago' , 'Set' , 'Out' , 'Nov' , 'Dez' )
Índice | Valor |
---|---|
0 | Jan |
1 | Fev |
2 | Mar |
3 | Abr |
4 | Mai |
5 | Jun |
6 | Jul |
7 | Ago |
8 | Set |
9 | Out |
10 | Nov |
11 | Dez |
-
Dicionários são bons para armazenar dados que podem ser representados em uma tabela de duas colunas.
-
Eles armazenam coleções de dados em pares de chave/valor, sem ordenação específica.
-
Um dicionário é delimitado por chaves e conjuntos de Chave/Valor separados por vírgula.
-
Um sinal de dois pontos é colocado entre cada chave e valor. Vírgulas separam pares de chave:valor.
{ 'TP53' : 'GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC' , 'BRCA1' : 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA' }
Chave | Valor |
---|---|
TP53 | GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC |
BRCA1 | GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA |
Parâmetros de linha de comando são colocados após o nome do script ou programa. Antes do primeiro parâmetro e entre parâmetros adicionais há espaçamento.
Os parâmetros permitem ao usuário fornecer informação ao script quando ele está sendo executado. Python armazena cada trecho do comando em uma lista especial chamada sys.argv
.
Você precisará importar o módulo chamado sys
no início do seu script desta forma:
#!/usr/bin/env python3
import sys
Vamos imaginar que um script é chamado amigos.py
. Se você escrever isso na linha de comando:
$ amigos.py Maria Carlos
Isso acontece dentro do script:
o nome do script 'amigos.py' e as strings 'Maria' e 'Carlos' aparecem na lista chamada
sys.argv
.
Estes são os parâmetros da linha de comando, ou argumentos que queira passar para o script.
sys.argv[0]
é o nome do script. Você pode acessar valores dos outros parâmetros pelos seus índices, começando com 1, entãosys.argv[1]
contém 'Maria' esys.argv[2]
contém 'Carlos'. Você acessa elementos em uma lista adicionando colchetes e o índice numérico depois do nome da lista.
Se você quisesse imprimir uma mensagem dizendo que estas duas pessoas são amigas, você poderia escrever um código como este
#!/usr/bin/env python3
import sys
friend1 = sys.argv[1] # obtém o parâmetro do primeiro comando
friend2 = sys.argv[2] # obtém o parâmetro do segundo comando
# agora a mensagem será exibida na tela
print(friend1,'e',friend2,'são amigos')
A vantagem de obter input do usuário da linha de comando é que você pode escrever um script que é genérico. Ele pode imprimir uma mensagem com qualquer input que o usuário fornecer. Isso o torna flexível. O usuário também fornece todos os dados que o script precisa na linha de comando de forma que o script não precisa pedir ao usuário para inserir o nome e esperar até que o usuário o faça. O script pode rodar por conta própria sem mais interações do usuário. Isso permite que o usuário trabalhe em outra coisa. Muito prático!
Você tem um identificador no seu código chamado dados
. Isso representa uma string, uma lista ou um dicionário? Python tem algumas funções que ajudam a descobrir isso.
Função | Descrição |
---|---|
type(dados) |
diz a qual classe seu objeto pertence |
dir(dados) |
diz quais métodos estão disponíveis para o seu objeto |
id(dados) |
diz qual o identificador único do seu objeto |
Nós cobriremos dir()
em mais detalhes mais adiante.
>>> data = [2,4,6]
>>> type(data)
<class 'list'>
>>> data = 5
>>> type(data)
<class 'int'>
>>> id(data)
44990666544
Um operador em uma linguagem de programação é um símbolo que faz o cumpridor ou intérprete performar operações matemáticas, relativas ou lógicas e produzir um resultado. Aqui explicaremos o conceito de operadores.
Em Python nós podemos escrever declarações que performam cálculos matemáticos. Para fazer isso nós precisamos usar operadores que são específicos para este propósito. Aqui estão operadores aritméticos:
Operador | Descrição | Exemplo | Resultado |
---|---|---|---|
+ |
Adição | 3+2 |
5 |
- |
Subtração | 3-2 |
1 |
* |
Multiplicação | 3*2 |
6 |
/ |
Divisão | 3/2 |
1.5 |
% |
Módulo (divide o operador da esquerda pelo da direita e retorna o resto) | 3%2 |
1 |
** |
Expoente | 3**2 |
9 |
// |
Divisão de piso (resultado é o quociente com os dígitos depois do ponto removidos). | 3//2 -11//3 |
1 -4 |
Módulo
Exemplos de piso
>>> 3/2
1.5
>>> 3//2
1
>>> -11/3
-3.6666666666666665
>>> -11//3
-4
>>> 11/3
3.6666666666666665
>>> 11//3
3
Nós usamos operadores de atribuição para atribuir valores para variáveis. Você tem usado =
como operador de atribuição. aqui estão outros:
Operador | Equivalente a | Exemplo | resultado assume o valor |
---|---|---|---|
= |
a = 3 |
result = 3 |
3 |
+= |
result = result + 2 |
result = 3 ; result += 2 |
5 |
-= |
result = result - 2 |
result = 3 ; result -= 2 |
1 |
*= |
result = result * 2 |
result = 3 ; result *= 2 |
6 |
/= |
result = result / 2 |
result = 3 ; result /= 2 |
1.5 |
%= |
result = result % 2 |
result = 3 ; result %= 2 |
1 |
**= |
result = result ** 2 |
result = 3 ; result **= 2 |
9 |
//= |
result = result // 2 |
result = 3 ; result //= 3 |
1 |
Estes operadores comparam dois valores e retornam verdadeiro ou falso.
Operador | Descrição | Exemplo | Resultado |
---|---|---|---|
== |
Igual a | 3 == 2 |
Falso |
!= |
Diferente de | 3 != 2 |
Verdadeiro |
> |
Maior que | 3 > 2 |
Verdadeiro |
< |
Menor que | 3 < 2 |
Falso |
>= |
Maior ou igual que | 3 >= 2 |
Verdadeiro |
<= |
Menor ou igual que | 3 <= 2 |
Falso |
Operadores lógicos permitem combinar dois ou mais conjuntos de comparações. Você pode combinar os resultados de diferentes formas. Por exemplo, você pode 1) querer que todas as declarações sejam verdadeiras, 2) que apenas uma declaração precise ser verdadeira, ou 3) que a declaração precise ser falsa.
Operador | Descrição | Exemplo | Resultado |
---|---|---|---|
and |
Verdadeiro se o operador da esquerda e o da direita forem verdade | 3>=2 and 2<3 |
Verdadeiro |
or |
Verdadeiro se o operador da esquerda ou o da direita forem verdade | 3==2 or 2>3 |
Falso |
not |
Inverte o status lógico | not False |
Verdadeiro |
Você pode testar para ver se o valor é incluído em uma string, tupla ou lista. Você pode também testar que o valor não está incluso na string, tupla ou lista.
Operador | Descrição |
---|---|
in |
Verdadeiro se o valor é incluso em uma lista, tupla ou string |
not in |
Verdadeiro se o valor é ausente em uma lista, tupla ou string |
Por Exemplo:
>>> frutas = ['maca', 'laranja', 'manga', 'tomate']
>>> 'manga' in frutas
True
>>>
>>> 'pera' in frutas
False
Outro exemplo:
>>> dna = 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA'
>>> 'TCT' in dna
True
>>>
>>> 'ATG' in dna
False
>>> 'ATG' not in dna
True
>>> codons = [ 'atg' , 'aaa' , 'agg' ]
>>> 'atg' in codons
True
>>> 'ttt' in codons
False
Operadores são listados em ordem de precedência. Os maiores listados primeiro. Nem todos operadores listados aqui são mencionados acima.
Operador | Descrição |
---|---|
** |
Exponenciação (Eleva o poder) |
~ + - |
Complemento binário mais e menos (nomes de métodos que os dois últimos são +@ e -@) |
* / % // |
Multiplica, divide, módulo e divisão de piso |
+ - |
Adição e subtração |
>> << |
Deslocamento binário parte por parte de direita e esquerda |
& |
Deslocamento binário 'AND' |
^ | |
Bitwise exclusivo 'OR' e regular 'OR' |
<= < > >= |
Operadores de comparação |
<> == != |
Operadores de igualdade ('<>' obsoleto no python 3) |
= %= /= //= -= += *= **= |
Operadores de atribuição |
is |
Operadores de identidade |
is not |
Operador de não identidade |
in |
Operador de filiação |
not in |
Operador de filiação negativa |
not or and |
Operadores lógicos |
Nota: Saiba mais a respeito bitwise operators.
Vamos voltar um pouco... O que é verdade?
Tudo é verdade, exceto por:
expressão | VERDADEIRO/FALSO |
---|---|
0 |
FALSO |
None |
FALSO |
False |
FALSO |
'' (string vazia) |
FALSO |
[] (lista vazia) |
FALSO |
() (tupla vazia) |
FALSO |
{} (dicionário vazio) |
FALSO |
O que significa que estes são verdade:
expressão | VERDADEIRO/FALSO |
---|---|
'0' |
VERDADEIRO |
'None' |
VERDADEIRO |
'False' |
VERDADEIRO |
'True' |
VERDADEIRO |
' ' (string de um espaço vazio) |
VERDADEIRO |
bool()
é uma função que testará se um valor é verdade.
>>> bool(True)
True
>>> bool('True')
True
>>>
>>>
>>> bool(False)
False
>>> bool('False')
True
>>>
>>>
>>> bool(0)
False
>>> bool('0')
True
>>>
>>>
>>> bool('')
False
>>> bool(' ')
True
>>>
>>>
>>> bool(())
False
>>> bool([])
False
>>> bool({})
False
Declarações de controle são usadas para direcionar o fluxo do seu código e criar oportunidade para tomada de decisão. Os fundamentos das declarações de controle são construídas por expressões verdadeiras.
- Use a declaração
if
para testar a verdade e executar linhas do código caso seja verdade. - Quando a expressão é avaliada como verdadeira, cada uma das declarações recuadas abaixo da declaração
if
, também conhecidas como o bloco de declarações aninhadas, será executada.
if
expressão if :
declaração
declaração
Por Exemplo:
dna = 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA'
if 'AGC' in dna:
print('found AGC in your dna sequence')
Retorna:
found AGC in your dna sequence
else
- A porção
if
da declaração if/else statement se comporta como antes. - O primeiro bloco recuado é executado se a condição é verdadeira.
- Se a condição for falsa, o segundo bloco else recuado é executado.
dna = 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA'
if 'ATG' in dna:
print('found ATG in your dna sequence')
else:
print('did not find ATG in your dna sequence')
Retorna:
did not find ATG in your dna sequence
- A condição
if
é testada como antes, e o bloco recuado é executado caso a condição for verdadeira. - Se for falsa, o bloco recuado seguindo o
elif
é executado se a primeira condiçãoelif
for verdadeira. - Quaisquer condições restantes
elif
serão testadas em ordem até que uma verdadeira for encontrada. Se nenhuma for, o bloco recuadoelse
é executado.
count = 60
if count < 0:
message = "é menor que 0"
print(count, message)
elif count < 50:
message = "é menor que 50"
print (count, message)
elif count > 50:
message = "é maior que 50"
print (count, message)
else:
message = "deve ser 50"
print(count, message)
Retorna:
60 é maior que 50
Vamos mudar a contagem para 20, qual declaração será executada?
count = 20
if count < 0:
message = "é menor que 0"
print(count, message)
elif count < 50:
message = "é menor que 50"
print (count, message)
elif count > 50:
message = "é maior que 50"
print (count, message)
else:
message = "deve ser 50"
print(count, message)
Retorna:
20 é menor que 50
O que acontece quando a contagem é 50?
count = 50
if count < 0:
message = "é menor que 0"
print(count, message)
elif count < 50:
message = "é menor que 50"
print (count, message)
elif count > 50:
message = "é maior que 50"
print (count, message)
else:
message = "deve ser 50"
print(count, message)
Retorna:
50 deve ser 50
Python reconhece 3 tipos de números: inteiros, números de ponto flutuante e números complexos.
- Conhecidos como int
- Um int pode ser positivo ou negativo
- e não contém um ponto decimal ou expoente.
- Conhecido como float
- Um ponto flutuante pode ser positivo ou negativo
- E contém um ponto decimal (
4.875
) ou expoente (4.2e-12
)
- conhecido como complex
- está na forma de a+bi onde bi é uma parte imaginária.
Às vezes um tipo de número precisa ser mudado por outro para a função poder trabalhar. Aqui está a lista de funções para converter tipos de números:
função | Descrição |
---|---|
int(x) |
para converter x para um inteiro simples |
float(x) |
para converter x para um número de ponto flutuante |
complex(x) |
para converter x para um número complexo com parte real x e parte imaginária zero |
complex(x, y) |
para converter x e y para um número complexo com parte real x e parte imaginária y |
>>> int(2.3)
2
>>> float(2)
2.0
>>> complex(2.3)
(2.3+0j)
>>> complex(2.3,2)
(2.3+2j)
Aqui está a lista de funções que usam números como argumentos. Elas são úteis como arredondamento.
função | Descrição |
---|---|
abs(x) |
O valor absoluto de x: a distância (positiva) entre x e zero. |
round(x,n) |
x arredondado para n dígitos do ponto decimal. round() arredonda para um inteiro se o valor é exatamente entre dois inteiros, então round(0.5) é 0 e round(-0.5) é 0. round(1.5) é 2. Arredondar para um número fixo de lugares decimais pode fornecer resultados imprevisíveis. |
max(x1, x2,...) |
O maior argumento é retornado |
min(x1, x2,...) |
O menor argumento é retornado |
>>> abs(2.3)
2.3
>>> abs(-2.9)
2.9
>>> round(2.3)
2
>>> round(2.5)
2
>>> round(2.9)
3
>>> round(-2.9)
-3
>>> round(-2.3)
-2
>>> round(-2.009,2)
-2.01
>>> round(2.675, 2) # Observe que este arredonda para baixo
2.67
>>> max(4,-5,5,1,11)
11
>>> min(4,-5,5,1,11)
-5
Muitas funções numéricas não são construídas dentro da central do Python e precisam ser importadas para dentro do script se quisermos usá-las. Para incluir elas, no topo do script digite:
import math
Estas próximas funções são encontradas no módulo matemático e precisam ser importadas. Para usá-las, preceda a função com o nome do módulo, i.e, math.ceil(15.5)
math.function | Descrição |
---|---|
math.ceil(x) |
retorna o menor inteiro maior ou igual que x |
math.floor(x) |
retorna o maior inteiro menor ou igual que x |
math.exp(x) |
O exponencial de x: ex é retornado |
math.log(x) |
O logaritmo natural de x, para x > 0 é retornado |
math.log10(x) |
O logaritmo de base 10 de x para x > 0 é retornado |
math.modf(x) |
As partes fracionárias e inteiras de x são retornadas em uma tupla de dois itens |
math.pow(x,y) |
O valor de x criado pelo poder y é retornado |
math.sqrt(x) |
Retorna a raíz quadrada de x para x >= 0 |
>>> import math
>>>
>>> math.ceil(2.3)
3
>>> math.ceil(2.9)
3
>>> math.ceil(-2.9)
-2
>>> math.floor(2.3)
2
>>> math.floor(2.9)
2
>>> math.floor(-2.9)
-3
>>> math.exp(2.3)
9.974182454814718
>>> math.exp(2.9)
18.17414536944306
>>> math.exp(-2.9)
0.05502322005640723
>>>
>>> math.log(2.3)
0.8329091229351039
>>> math.log(2.9)
1.0647107369924282
>>> math.log(-2.9)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: math domain error
>>>
>>> math.log10(2.3)
0.36172783601759284
>>> math.log10(2.9)
0.4623979978989561
>>>
>>> math.modf(2.3)
(0.2999999999999998, 2.0)
>>>
>>> math.pow(2.3,1)
2.3
>>> math.pow(2.3,2)
5.289999999999999
>>> math.pow(-2.3,2)
5.289999999999999
>>> math.pow(2.3,-2)
0.18903591682419663
>>>
>>> math.sqrt(25)
5.0
>>> math.sqrt(2.3)
1.51657508881031
>>> math.sqrt(2.9)
1.70293863659264
Algumas vezes, é necessário comparar dois números e descobrir se o primeiro é menor, igual ou maior que o segundo.
A simples função cmp(x,y)
não é disponível em Python 3.
Use este idioma ao invés:
cmp = (x>y)-(x<y)
Ele retorna três diferentes valores dependendo do x e do y
-
se x<y, o -1 é retornado
-
se x>y, o 1 é retornado
-
x == y, o 0 é retornado
Na próxima seção, nós iremos aprender sobre strings, tuplas, e listas. Todos estes são exemplos de sequências em python. uma sequência de caracteres 'ACGTGA'
, uma tupla (0.23, 9.74, -8.17, 3.24, 0.16)
, e uma lista ['dog', 'cat', 'bird']
são sequências de diferentes tipos de dados. Veremos mais detalhes em breve.
Em Python, um tipo de objeto consegue operações que pertencem àquele tipo. Sequências têm operações sequenciais então as strings também podem usar operações sequenciais. Strings também possuem suas próprias operações específicas.
Você pode perguntar qual a extensão de qualquer sequência
>>>len('ACGTGA') # extensão de uma string
6
>>>len( (0.23, 9.74, -8.17, 3.24, 0.16) ) # extensão de uma tupla, precisa de dois parênteses (( ))
5
>>>len(['dog', 'cat', 'bird']) # extensão de uma lista
3
Você pode também usar funções de strings específicas, mas não em listas e vice-versa. Nós vamos aprender mais sobre isso posteriormente. rstrip()
é um método de string ou função. Você obtém um erro se você tentar usar isso em uma lista.
>>> 'ACGTGA'.rstrip('A')
'ACGTG'
>>> ['dog', 'cat', 'bird'].rstrip()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'rstrip'
Como descobrir quais funções servem com um objeto? Existe uma função prática dir()
. Como um exemplo quais funções você pode acionar em sua string 'ACGTGA'
?
>>> dir('ACGTGA')
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
dir()
irá retornar todos os atributos de um objeto, dentre eles estão funções. Tecnicamente, funções pertencentes a uma classe específica (tipo de objeto) são chamadas de métodos.
Você pode chamar dir()
em qualquer objeto, mais comumente, você usará isso na esfera interativa do Python.
- Uma string é uma série de caracteres começando e terminando com marcas de aspas únicas ou duplas.
- Strings são um exemplo de uma sequência de Python. Uma sequência é definida como um grupo ordenado posicionalmente. Isso significa que cada elemento no grupo tem uma posição, começando com zero, i.e. 0,1,2,3 e assim até você chegar no final da string.
- Única (')
- Dupla (")
- Tripla (''' or """)
Notas sobre as aspas:
- Aspas únicas e duplas são equivalentes.
- O nome de uma variável dentro das sentenças é apenas o identificador da string, não o valor armazenado dentro da variável.
format()
é útil para interpolação de variáveis em python - Sentenças: Aspas triplas (únicas ou dobradas) são usadas antes e depois de uma string que abrange múltiplas linhas.
Uso de exemplos das aspas:
palavra = 'word'
sentença = "This is a sentence."
parágrafo = """Isso é um parágrafo. Isso é feito de múltiplas linhas e sentenças.
E assim vai.
"""
Nós vimos exemplos de print()
antes. Vamos conversar sobre isso um pouco mais. print()
é uma função que assume um ou mais argumentos separados por vírgulas.
Vamos usar a função print()
para imprimir uma string.
>>>print("ATG")
ATG
Vamos atribuir uma string a uma variável e imprimir a variável.
>>>dna = 'ATG'
ATG
>>> print(dna)
ATG
O que acontece se nós colocarmos o nome da variável dentro de aspas?
>>>dna = 'ATG'
ATG
>>> print("dna")
dna
A string literal 'dna' é impressa na tela, não o conteúdo 'ATG'
Vamos ver o que acontece quando nós demos print()
em duas strings literais como argumentos.
>>> print("ATG","GGTCTAC")
ATG GGTCTAC
Nós conseguimos as duas strings literais impressas na tela separadas por um espaço
E se você não quiser suas strings separadas por um espaço? use o operador concatenação para concatenar as duas strings antes ou dentro da função print()
.
>>> print("ATG"+"GGTCTAC")
ATGGGTCTAC
>>> combined_string = "ATG"+"GGTCTAC"
ATGGGTCTAC
>>> print(combined_string)
ATGGGTCTAC
Nós conseguimos duas strings impressas na tela sem ser separadas por um espaço. Você pode também usar isso
>>> print('ATG','GGTCTAC',sep='')
ATGGGTCTAC
Agora, vamos imprimir uma variável e uma string literal.
>>>dna = 'ATG'
ATG
>>> print(dna,'GGTCTAC')
ATG GGTCTAC
Nós conseguimos o valor da variável e a string literal impressa na tela separada por um espaço
Como poderíamos imprimir os dois sem um espaço?
>>>dna = 'ATG'
ATG
>>> print(dna + 'GGTCTAC')
ATGGGTCTAC
Algo para se pensar sobre: valores de variáveis são variáveis. Em outras palavras, eles são mutáveis e alteráveis.
>>>dna = 'ATG'
ATG
>>> print(dna)
ATG
>>>dna = 'TTT'
TTT
>>> print(dna)
TTT
O novo valor da variável 'dna' é impresso no visor quando
dna
é um argumento para a funçãoprint()
.
Vamos olhar os erros típicos que você encontrará quando usar a função print()
.
O que acontecerá se você esquecer de fechar suas sentenças?
>>> print("GGTCTAC)
File "<stdin>", line 1
print("GGTCTAC)
^
SyntaxError: EOL while scanning string literal
Nós obtemos um'SyntaxError' se a sentença de encerramento não for usada.
O que acontecerá se você se esquecer de incluir uma string que você quer imprimir nas sentenças?
>>> print(GGTCTAC)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'GGTCTAC' is not defined
Nós obtemos um 'NameError' quando a string literal não for incluída nas sentenças porque o Python está procurando uma variável com o nome GGTCTAC
>>> print "boo"
File "<stdin>", line 1
print "boo"
^
SyntaxError: Missing parentheses in call to 'print'
Em python2, o comando era print
, mas isso mudou para print()
em python3, então não se esqueça dos parênteses!
Como você incluiria uma nova linha, retorno de transporte, ou tab em sua string?
Caractere de escape | Descrição |
---|---|
\n | Nova linha |
\r | Retorno de carro |
\t | Tab |
Vamos incluir alguns caracteres de escape em suas strings e funções print()
.
>>> string_with_newline = 'esta string possuí uma quebra de linha\nesta é a segunda linha'
>>> print(string_with_newline)
esta string possuí uma quebra de linha
esta é a segunda linha
Nós imprimimos uma nova linha na tela
print()
adiciona espaços entre argumentos e uma nova linha ao final. Você pode mudar isso com sep=
e end=
. Aqui está um exemplo:
print('uma linha', 'segunda linha' , 'terceira linha', sep='\n', end = '')
Uma forma mais limpa para fazer isso é expressar uma string de múltiplas linhas inclusa em aspas triplas (""").
>>> print("""esta string possuí uma quebra de linha
... esta é a segunda linha""")
esta string possuí uma quebra de linha
esta é a segunda linha
Vamos imprimir um caractere tab (\t).
>>> line = "valor1\tvalor2\tvalor3"
>>> print(line)
valor1 valor2 valor3
Nós obtemos as três palavras separadas por caracteres tab. Um formato comum para dados é separar colunas com tabs como isso.
Você pode adicionar uma barra invertida antes de qualquer caractere para forçar de ser impresso como um literal. Isso é chamado 'escaping'. Só é realmente útil para imprimir sentenças literais ' e "
>>> print('esta é uma \'palavra\'') # se você quiser imprimir um ' dentro: '...'
esta é uma 'palavra'
>>> print("esta é uma 'palavra'") # talvez mais claro para imprimir um ' dentro "..."
esta é uma 'palavra'
Em ambos os casos a sentença atual única é impressa na tela
Se você quiser todos caracteres em sua string para permanecer exatamente como são, declare sua string uma string crua literal com 'r' antes da primeira sentença. Isso parece feio, mas funciona.
>>> line = r"valor1\tvalor2\tvalor3"
>>> print(line)
valor1\tvalor2\tvalor3
Nossos caracteres de escape '\t' estão como nós digitamos, eles não são convertidos para caracteres tab de fato.
Para concatenar strings use o operador de concatenação '+'
>>> promoter= 'TATAAA'
>>> upstream = 'TAGCTA'
>>> downstream = 'ATCATAAT'
>>> dna = upstream + promoter + downstream
>>> print(dna)
TAGCTATATAAAATCATAAT
O operador de concatenação pode ser usado para combinar strings. A nova combinação de strings pode ser armazenada em uma variável.
O que acontece se você usar +
com números (estes são inteiros ou ints)?
>>> 4+3
7
Para strings, +
concatena; para inteiros, +
soma.
Você precisa converter os números para strings antes de poder concatená-las
>>> str(4) + str(3)
'43'
Use a função len()
para calcular a extensão de uma string. Essa função assume a sequência como um argumento e retorna uma int
>>> print(dna)
TAGCTATATAAAATCATAAT
>>> len(dna)
20
A extensão de uma string, incluindo espaços, é calculada e apresentada.
O valor que len()
retorna pode ser armazenado em uma variável.
>>> dna_length = len(dna)
>>> print(dna_length)
20
Você pode misturar strings e ints em print()
, mas não em concatenação.
>>> print("The length of the DNA sequence:" , dna , "is" , dna_length)
The length of the DNA sequence: TAGCTATATAAAATCATAAT is 20
Alterando o caso da string é um pouco distinto do que você pode esperar inicialmente. Por exemplo, para diminuir uma string precisamos utilizar um método. Um método é uma função específica para um objeto. Quando nós assumimos uma string a uma variável estamos criando uma instância de um objeto de string. Esse objeto tem uma série de métodos que funcionarão nos dados que estão armazenados no objeto. Lembre-se que dir()
irá te dizer todos os métodos que estão disponíveis para um objeto. A função lower()
é um método de string.
Vamos criar um novo objeto de string.
dna = "ATGCTTG"
Parece familiar?
Agora que nós temos um objeto de string nós podemos usar os métodos de string. A forma que você utiliza um método consiste em inserir um '.' entre o objeto e o nome do método.
>>> dna = "ATGCTTG"
>>> dna.lower()
'atgcttg'
o método lower() retorna os conteúdos armazenados na variável 'dna' em letra minúscula.
Os conteúdos da variável 'dna' não se alteraram. Strings são imutáveis. Se você quiser manter a versão minúscula de uma string, armazene ela em uma nova variável.
>>> print(dna)
ATGCTTG
>>> dna_lowercase = dna.lower()
>>> print(dna)
ATGCTTG
>>> print(dna_lowercase)
atgcttg
O método de string pode ser guardado dentro de outras funções.
>>> dna = "ATGCTTG"
>>> print(dna.lower())
atgcttg
Os conteúdos de 'dna' são transformados em minúsculos e transportados para a função
print()
.
Se você tentar usar um método de string em um objeto que não é uma string você receberá um erro.
>>> nt_count = 6
>>> dna_lc = nt_count.lower()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'lower'
Você obtém um AttributeError quando você usa um método em um tipo de objeto incorreto. Nós recebemos que o objeto int (um int é retornado por
len()
) não tem uma função chamada inferior.
Vamos tornar uma string maiúscula agora.
>>> dna = 'attgct'
>>> dna.upper()
'ATTGCT'
>>> print(dna)
attgct
Os conteúdos de uma variável 'dna' são retornados em maiúsculo. Os conteúdos de 'dna' não foram alterados.
O índice posicional de uma string exata em uma string maior pode ser encontrado e retornado com o método de string
find()
. Uma string exata é dada como um argumento e o índice de sua primeira ocorrência é retornado. -1 é retornado se nada for encontrado.
>>> dna = 'ATTAAAGGGCCC'
>>> dna.find('T')
1
>>> dna.find('N')
-1
O subtermo 'T' é encontrado pela primeira vez no índice 1 na string 'dna' então 1 é retornado. O subtermo 'N' não foi encontrado, então -1 é retornado.
count(str)
retorna o número (como um int) que se encaixa exatamente com a string que encontrou
>>> dna = 'ATGCTGCATT'
>>> dna.count('T')
4
O número de vezes que 'T' for encontrado é retornado. A string armazenada em 'dna' não é alterada.
replace(str1,str2)
retorna uma nova string com todas as combinações de str1
em uma string substituída com str2
.
>>> dna = 'ATGCTGCATT'
>>> dna.replace('T','U')
'AUGCUGCAUU'
>>> print(dna)
ATGCTGCATT
>>> rna = dna.replace('T','U')
>>> print(rna)
AUGCUGCAUU
Todas as ocorrências de T são substituídas por U. A nova string é retornada. A string original não foi de fato alterada. Se você quiser reutilizar a nova string, armazene ela em uma variável.
Partes de uma string podem ser localizadas baseadas na posição e retornadas. Isso é porque uma string é uma sequência. Coordenadas começam em 0. Você adiciona a coordenada em colchetes depois do nome da string.
Você pode chegar a qualquer parte da string com a seguinte sentença [start : end : step].
Essa string 'ATTAAAGGGCCC' é feita da seguinte sequência de caracteres, e posições (começando em zero).
Posição/Índice | Caractere |
---|---|
0 | A |
1 | T |
2 | T |
3 | A |
4 | A |
5 | A |
6 | G |
7 | G |
8 | G |
9 | C |
10 | C |
11 | C |
Vamos retornar os 4°, 5° e 6° nucleotídeos. Para isso, nós precisamos começar contando em 0 e lembrando que o python conta os vãos entre cada caractere, começando com zero.
index 0 1 2 3 4 5 6 7 8 ...
string A T T A A A G G ...
>>> dna = 'ATTAAAGGGCCC'
>>> sub_dna = dna[3:6]
>>> print(sub_dna)
AAA
Os caracteres com índices 3, 4, 5 são retornados. Em outras palavras, todo caractere começando com o índice 3 e acima, mas não incluindo acima ou igual ao índice 6.
Vamos retornar os primeiros 6 caracteres.
>>> dna = 'ATTAAAGGGCCC'
>>> sub_dna = dna[0:6]
>>> print(sub_dna)
ATTAAA
Todo caractere começando no índice 0 e acima, mas não incluindo o de índice 6 e acima, são retornados. Esse é o mesmo que dna[:6]
Vamos retornar todos os caracteres do índice 6 até o fim da string.
>>> dna = 'ATTAAAGGGCCC'
>>> sub_dna = dna[6:]
>>> print(sub_dna)
GGGCCC
Quando o segundo argumento é deixado em branco, todos caracteres do índice 6 e acima são retornados.
Vamos retornar os últimos 3 caracteres.
>>> sub_dna = dna[-3:]
>>> print(sub_dna)
CCC
Quando o segundo argumento é deixado em branco e o primeiro argumento é negativo (-X), X caracteres do final da string são retornados.
Não existe função de reverso, você precisa usar uma fatia com patamar -1 e início e fim vazios.
Para uma string, se parece com isso
>>> dna='GATGAA'
>>> dna[::-1]
'AAGTAG'
Desde que estes são métodos, se certifique de utilizar na sentença string.method()
.
função | Descrição |
---|---|
s.strip() |
retorna uma string com o espaço em branco removido do começo e fim |
s.isalpha() |
testa se todos caracteres da string são alfabéticos. Retorna verdadeiro ou falso. |
s.isdigit() |
testa se todos caracteres da string são numéricos. Retorna verdadeiro ou falso. |
s.startswith('other_string') |
testa se a string começa com a string fornecida como argumento. Retorna verdadeiro ou falso. |
s.endswith('other_string') |
testa se a string termina com a string fornecida como argumento. Retorna verdadeiro ou falso. |
s.split('delim') |
separa a string no delimitador exato fornecido. Retorna a lista de subtermos. Se o argumento é fornecido, a string será separada no espaço em branco. |
s.join(list) |
O oposto de split() . Os elementos de uma lista serão concatenados juntos usando a string armazenada em 's' como um delimitadoras. |
split
split
é um método ou forma de partir uma string em um grupo de caracteres. O que é retornado é uma lista de elementos com caracteres que são usados para partir removidos. Veremos as listas com mais detalhes na próxima seção. Não se preocupe com isso.
Vamos olhar para essa string:
00000xx000xx000000000000xx0xx00
Vamos separar em 'xx' e obter uma lista dos 0's
O que é o 's' em s.split(delim)
?
O que é 'delim' em s.split(delim)
?
Vamos tentar isso:
>>> string_to_split='00000xx000xx000000000000xx0xx00'
>>> string_to_split.split('xx')
['00000', '000', '000000000000', '0', '00']
>>> zero_parts = string_to_split.split('xx')
>>> print(zero_parts)
['00000', '000', '000000000000', '0', '00']
Nós começamos com uma string e agora temos uma lista com todos os delimitadores removidos
Aqui está outro exemplo. Vamos dividir em tabs para obter uma lista dos números em colunas separadas por tab.
>>> input_expr = '4.73\t7.91\t3.65'
>>> expression_values = input_expr.split('\t')
>>> expression_values
['4.73', '7.91', '3.65']
join
join
é um método ou uma forma de pegar uma lista de elementos, de coisas, e transformar em uma string com algo posto entre cada elemento. A lista será coberta na próxima seção com mais detalhes.
Vamos aplicar em uma lista de Ns list_of_Ns = ['NNNNN', 'NNN', 'N', 'NNNNNNNNNNNNNNN', 'NN']
em 'xx' para obter essa string:
NNNNNxxNNNxxNxxNNNNNNNNNNNNNNNxxNN
O que é o 's' em s.join(list)
?
O que é a 'list' em s.join(list)
?
>>> list_of_Ns = ['NNNNN', 'NNN', 'N', 'NNNNNNNNNNNNNNN', 'NN']
>>> list_of_Ns
['NNNNN', 'NNN', 'N', 'NNNNNNNNNNNNNNN', 'NN']
>>>
>>> string_of_elements_with_xx = 'xx'.join(list_of_Ns)
>>> string_of_elements_with_xx
'NNNNNxxNNNxxNxxNNNNNNNNNNNNNNNxxNN'
Nós começamos com uma lista e agora temos todos os elementos em uma string com o delimitador adicionado entre cada elemento.
Vamos pegar uma lista de valores de expressão e criar uma string delimitada por tab que abrirá bem em uma planilha com cada valor em sua própria coluna:
>>> expression_values = ['4.73', '7.91', '3.65']
>>>expression_values
['4.73', '7.91', '3.65']
>>> expression_value_string = '\t'.join(expression_values)
>>> expression_value_string
'4.73\t7.91\t3.65'
imprima isso em um arquivo e abra ele em Excel, é lindo!!
Strings podem ser formatadas usando a função format()
. Bem intuitivo, mas espere até ver os detalhes! Por exemplo, se você quiser incluir strings literais e variáveis em sua declaração de impressão e não quer concatenar ou usar múltiplos argumentos na função print()
você pode usar formatação de string.
>>> string = "Esta sequência: {} possui {} nucleotídeos e é encontrada em {}."
>>> string.format(dna,dna_len,gene_name)
'Esta sequência: TGAACATCTAAAAGATGAAGTTT possui 23 nucleotídeos e é encontrada em Brca1.'
>>> print(string) # string.format() não altera a string original
Esta sequência: {} possui {} nucleotídeos e é encontrada em {}.
>>> new_string = string.format(dna,dna_len,gene_name)
>>> print(new_string)
Esta sequência: TGAACATCTAAAAGATGAAGTTT possui 23 nucleotídeos e é encontrada em Brca1.
Nós colocamos juntamente três variáveis e strings literais em uma string única usando a função format()
. A string original não é alterada, uma nova string é retornada e incorpora os argumentos. Você pode salvar o valor retornado em uma nova variável. Cada {}
é um espaço reservado para a string que precisa ser inserida.
Algo legal sobre format()
é que você pode imprimir int e tipos variáveis de string sem converter primeiramente.
Você pode também chamar diretamente format()
dentro de uma função print()
. Aqui estão dois exemplos
>>> string = "Esta sequência: {} possui {} nucleotídeos e é encontrada em {}."
>>> print(string.format(dna,dna_len,gene_name))
Esta sequência: TGAACATCTAAAAGATGAAGTTT possui 23 nucleotídeos e é encontrada em Brca1.
Ou use a função format()
em uma string literal:
>>> print( "Esta sequência: {} possui {} nucleotídeos e é encontrada em {}.".format(dna,dna_len,gene_name))
Esta sequência: TGAACATCTAAAAGATGAAGTTT possui 23 nucleotídeos e é encontrada em Brca1.
Até agora, nós usamos apenas {}
para mostrar onde inserir o valor de uma variável em uma string. Você pode adicionar caracteres especiais dentro de {}
para mudar a forma que a variável é formatada quando é inserida dentro da string.
Você pode numerar estes, não necessariamente em ordem.
>>> '{0}, {1}, {2}'.format('a', 'b', 'c')
'a, b, c'
>>> '{2}, {1}, {0}'.format('a', 'b', 'c')
'c, b, a'
Para mudar o espaçamento das strings e a forma que os números são formatados, você adiciona :
e outros caracteres especiais como isso {:>5}
para corrigir uma string em um campo de cinco caracteres
Vamos corrigir justificando alguns números.
>>> print( "{:>5}".format(2) )
2
>>> print( "{:>5}".format(20) )
20
>>> print( "{:>5}".format(200) )
200
E sobre preencher com zeros? Isso significa que o campo de cinco caracteres será preenchido conforme preciso com zeros a esquerda de quaisquer números que você quer apresentar
>>> print( "{:05}".format(2) )
00002
>>> print( "{:05}".format(20) )
00020
Use um <
para indicar justificação à esquerda.
>>> print( "{:<5} genes".format(2) )
2 genes
>>> print( "{:<5} genes".format(20) )
20 genes
>>> print( "{:<5} genes".format(200) )
200 genes
Alinhamento ao centro é feito com ^
ao invés de >
ou <
. Você pode também preencher com caracteres sem ser 0. Aqui vamos tentar _
ou sublinhar como em :_^
. O símbolo de preencher vai antes do símbolo de alinhamento.
>>> print( "{:_^10}".format(2) )
____2_____
>>> print( "{:_^10}".format(20) )
____20____
>>> print( "{:_^10}".format(200) )
___200____
Aqui estão algumas das opções de ALINHAMENTO:
Opção | Significado | |
---|---|---|
< |
Força o campo para estar alinhado à esquerda com o espaço disponível (Isso é o padrão para a maioria dos objetos). | |
> |
Força o campo para estar alinhado à direita com o espaço disponível (Isso é o padrão para números). | |
= |
Força o campo para o preenchimento ser posto depois do sinal (se tiver) mas antes dos dígitos. Isso é usado para imprimir campos na forma ‘+000000120’. Essa opção de alinhamento é apenas válida para tipos numéricos. | |
^ |
Força o campo para ser centralizado com o espaço disponível. |
Aqui está um exemplo
{ : x < 10 s}
preencher com
x
justificar à esquerda<
10
um campo com dez caracteress
uma string
Tipos comuns
tipo | descrição |
---|---|
b | converte para binário |
d | inteiro decimal |
e | expoente, precisão padrão é 6, usa e |
E | expoente, usa E |
f | ponto de flutuação, precisão padrão é 6 (também F) |
g | número genérico, flutua para valores próximos de 0, expoente para outros; também G |
s | string, tipo padrão (conforme exemplo acima) |
x | converte para hexadecimal, também X |
% | converte para % multiplicando por 100 |
Muito pode ser feito com a função format()
. Aqui está um último exemplo, mas não a última funcionalidade desta função, vamos arredondar um número de ponto de flutuação para algumas casas decimais, começando com muitos. (o padrão é 6). Note que a função arredonda para a casa decimal mais próxima, mas nem sempre exatamente da forma que você espera por conta da forma que os computadores representam decimais com 1s e 0s.
'{:f}'.format(3.141592653589793)
'3.141593'
>>> '{:.4f}'.format(3.141592653589793)
'3.1416'
Listas são tipos de dados que armazenam uma coleção de dados.
- Listas são usadas para armazenar uma coleção de dados de maneira ordenada e indexada.
- Valores são separados por vírgulas
- Valores são anexados entre colchetes '[]'
- Listas podem crescer e encolher
- Valores são mutáveis
[ 'atg' , 'aaa' , 'agg' ]
- Tuplas são usadas para armazenar uma coleção de dados de maneira ordenada e indexada
- Valores são separados por vírgulas
- Valores são anexados entre parênteses '()'
- Tuplas NÃO podem crescer ou encolher
- Valores são imutáveis
( 'Jan' , 'Fev' , 'Mar' , 'Abr' , 'Mai' , 'Jun' , 'Jul' , 'Ago' , 'Set' , 'Out' , 'Nov' , 'Dez' )
Muitas funções e métodos retornam tuplas: O math.modf(x)
, por exemplo, retorna as partes fracionais e inteiras de x
em uma tupla de dois itens. Aqui não existem motivos para mudar a sequência.
>>> math.modf(2.6)
(0.6000000000000001, 2.0)
Para recuperar um valor em uma lista utilize o índice do valor nesse formato list[index]. Isso retornará o valor do índice especificado, começando com 0.
Aqui está uma lista:
>>> codons = [ 'atg' , 'aaa' , 'agg' ]
Existem 3 valores com os índices 0, 1, 2
Índice | Valor |
---|---|
0 | atg |
1 | aaa |
2 | agg |
Vamos acessar o valor de índice 0. Você vai precisar de um número de índice (0
) dentro de colchetes desta forma [0]
. Isso vai após o nome da lista (codons
)
>>> codons = [ 'atg' , 'aaa' , 'agg' ]
>>> codons[0]
'atg'
O valor pode ser salvo em uma variável, e ser usado depois.
>>> codons = [ 'atg' , 'aaa' , 'agg' ]
>>> first_codon = codons[0]
>>> print(first_codon)
atg
Cada valor pode ser salvo em uma nova variável para usar posteriormente.
Os valores podem ser recuperados e usados diretamente.
>>> codons = [ 'atg' , 'aaa' , 'agg' ]
>>> print(codons[0])
atg
>>> print(codons[1])
aaa
>>> print(codons[2])
agg
Outro exemplo com culturas:
>>> culturas = ['soja', 'milho', 'algodao', 'arroz']
>>> print(culturas[0])
soja
>>> print(culturas[1])
milho
>>> print(culturas[3])
arroz
Os 3 valores são acessados independentemente e impressos imediatamente. Eles não são armazenados em uma variável.
Mais um exemplo com números inteiros
>>> producao = [3000, 8000, 2000, 3000]
>>> print(producao[2])
Mas nessa lista com inteiros, podemos fazer algumas operações, por exemplo, somar os valores armazenados nos índices 1 e 2:
>>> producao[1] + producao[2]
>>> 10000
Se você deseja acessar os valores começando pelo fim da lista, use índices negativos.
>>> codons = [ 'atg' , 'aaa' , 'agg' ]
>>> print(codons[-1])
agg
>>> print(codons[-2])
aaa
Usar um índice negativo retornará os valores do final da lista. Por exemplo, -1 é o índice do último valor 'agg'. Esse valor também possui um índice de 2.
Ou com o exemplo das culturas
print(culturas[-1]) arroz
Valores individuais podem ser alterados usando o valor de índice e o operador de atribuição.
>>> print(codons)
['atg', 'aaa', 'agg']
>>> codons[2] = 'cgc'
>>> print(codons)
['atg', 'aaa', 'cgc']
E sobre atribuir um valor para um índice que não existe?
>>> codons[5] = 'aac'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
codon[5] não existe, e quando tentamos atribuir valor para esse índice ocorre um IndexError. Se você deseja adicionar novos elementos no final da lista use
codons.append('taa')
oucodons.extend(list)
. Veja mais detalhes abaixo.
Vamos acrescentar mais uma cultura na nossa lista de culturas: mandioca.
>>> culturas.append('mandioca')
print(culturas)
Isso funciona da mesma forma com as listas como com as strings. Isso é porque ambos são sequências, ou coleções ordenadas de dados com informação posicional. Lembre-se que Python conta as divisões entre os elementos, começando com 0.
Índice | Valor |
---|---|
0 | atg |
1 | aaa |
2 | agg |
3 | aac |
4 | cgc |
5 | acg |
use a sintaxe [start : end : step] para dividir sua sequência python
>>> codons = [ 'atg' , 'aaa' , 'agg' , 'aac' , 'cgc' , 'acg']
>>> print (codons[1:3])
['aaa', 'agg']
>>> print (codons[3:])
['aac', 'cgc', 'acg']
>>> print (codons[:3])
['atg', 'aaa', 'agg']
>>> print (codons[0:3])
['atg', 'aaa', 'agg']
codons[1:3]
retorna todo valor começando com o valor de codons[1] até, mas não incluindo, o codons[3]
codons[3:]
retorna todo valor começando com o valor de codons[3] e todos os valores posteriores.
codons[:3]
retorna todo valor até, mas não incluindo, codons[3]
codons[0:3]
é o mesmo quecodons[:3]
Operador | Descrição | Exemplo |
---|---|---|
+ |
Concatenação | [10, 20, 30] + [40, 50, 60] retorna [10, 20, 30, 40, 50, 60] |
* |
Repetição | ['atg'] * 4 retorna ['atg','atg','atg','atg'] |
in |
Filiação | 20 in [10, 20, 30] retorna True |
Funções | Descrição | Exemplo |
---|---|---|
len(list) |
retorna o comprimento ou o número de valores em uma lista | len([1,2,3]) retorna 3 |
max(list) |
retorna o valor com o maior ASCII (=último no alfabeto ASCII) | max(['a','A','z']) retorna 'z' |
min(list) |
retorna o valor com o menor ASCII (=primeiro no alfabeto ASCII) | min(['a','A','z']) retorna 'A' |
list(seq) |
converte uma tupla em uma lista | list(('a','A','z')) retorna ['a', 'A', 'z'] |
sorted(list, key=None, reverse=False) |
retorna uma lista organizada baseada na chave fornecida | sorted(['a','A','z']) retorna ['A', 'a', 'z'] |
sorted(list, key=str.lower, reverse=False) |
str.lower() faz com que os elementos minúsculos retornem antes na lista organizada |
sorted(['a','A','z'],key=str.lower) retorna ['a', 'A', 'z'] |
Lembre-se que métodos são utilizados no seguinte formato list.method().
Para esses exemplos utilize: nums = [1,2,3]
e codons = [ 'atg' , 'aaa' , 'agg' ]
Métodos | Descrição | Exemplo |
---|---|---|
list.append(obj) |
anexa um objeto no final de uma lista | nums.append(9) ; print(nums) ; retorna [1,2,3,9] |
list.count(obj) |
conta as ocorrências de um objeto em uma lista | nums.count(2) retorna 1 |
list.index(obj) |
retorna o menor índice em que o objeto fornecido é encontrado | nums.index(2) retorna 1 |
list.pop() |
remove e retorna o último valor de uma lista. A lista é agora um elemento mais curta | nums.pop() retorna 3 |
list.insert(index, obj) |
insere um valor ao índice fornecido. Lembre-se de pensar sobre as divisões entre os elementos | nums.insert(0,100) ; print(nums) retorna [100, 1, 2, 3] |
list.extend(new_list) |
anexa new_list ao final de list |
nums.extend([7, 8]) ; print(nums) retorna [1, 2, 3, 7,8] |
list.pop(index) |
remove e retorna o valor do argumento indexado. A lista é agora um valor mais curta | nums.pop(0) retorna 1 |
list.remove(obj) |
encontra o menor índice do objeto fornecido e o remove da lista. A lista é agora um elemento mais curta | codons.remove('aaa') ; print(codons) retorna [ 'atg' , 'agg' ] |
list.reverse() |
inverte a ordem da lista | nums.reverse() ; print(nums) retorna [3,2,1] |
list.copy() |
Retorna uma cópia rasa da lista. Rasa vs Deep apenas importa em estruturas de data multidimensionais. | |
list.sort([func]) |
organiza uma lista utilizando a função fornecida. Não retorna uma lista. A lista foi alterada. A organização avançada de listas será coberta adiante na discussão sobre escrever suas próprias funções. | codons.sort() ; print(codons) retorna ['aaa', 'agg', 'atg'] |
Tome cuidado em como você faz uma cópia de sua lista
>>> my_list=['a', 'um', 'dois']
>>> copy_list=my_list
>>> copy_list.append('1')
>>> print(my_list)
['a', 'um', 'dois', '1']
>>> print(copy_list)
['a', 'um', 'dois', '1']
Não foi o que esperava?! Ambas listas foram alteradas porque nós apenas copiamos um ponteiro para a lista original quando escrevemos
copy_list=my_list
.
Vamos copiar a lista utilizando o método copy()
.
>>> my_list=['a', 'um', 'dois']
>>> copy_list=my_list.copy()
>>> copy_list.append('1')
>>> print(my_list)
['a', 'um', 'dois']
Agora sim, nós obtivemos o esperado desta vez!
Agora que você já viu a função append()
nós podemos ver como construir uma lista com um valor por vez.
>>> words = []
>>> print(words)
[]
>>> words.append('um')
>>> words.append('dois')
>>> print(words)
['um', 'dois']
Nós começamos com uma lista vazia chamada 'words'. Nós usamos
append()
para adicionar o valor 'um' depois o valor 'dois'. Finalizamos a lista com dois valores. Você pode adicionar uma lista inteira em outra lista comwords.extend(['três','quatro','cinco'])
Todas as codificações pelas quais percorremos até então foram executadas linha por linha. Algumas vezes existem blocos de códigos que queremos executar mais do que uma vez. Loops permitem que façamos isso.
Existem dois tipos de loops:
- while loop
- for loop
O while loop vai continuar a executar um bloco de código enquanto a expressão de teste apresentar Verdadeiro
.
while expression:
# estas declarações são executadas sempre que o código entrar em loop
statement1
statement2
more_statements
# código logo abaixo é executado depois que o while loop encerrar
rest_of_code_goes_here
more_code
A condição é a expressão. O bloco de código while loop é uma coleção de declarações recuadas/indentadas seguindo a expressão.
Código:
#!/usr/bin/env python3
contagem = 0
while contagem < 5:
print("contagem:" , contagem)
contagem+=1
print("Done")
Saída:
$ python while.py
contagem: 0
contagem: 1
contagem: 2
contagem: 3
contagem: 4
Done
A condição while foi verdadeira 5 vezes e o bloco de código while foi executado 5 vezes.
- contagem é igual a 0 quando começamos
- 0 é menos que 5 então executamos o bloco while
- contagem é impressa
- contagem é incrementada (contagem = count + 1)
- contagem é agora igual a 1.
- 1 é menor que 5 então executamos o bloco while pela segunda vez.
- isso permanece até que a contagem seja 5.
- 5 não é menor que 5 então nós saímos do bloco while
- A primeira linha seguindo a declaração while é executada, "Done" é impresso
Um loop infinito ocorre quando uma condição while é sempre verdadeira. Aqui está um exemplo de um loop infinito.
#!/usr/bin/env python3
contagem = 0
while contagem < 5: # isso é normalmente um bug!!
print("contagem:" , contagem) # esqueça de incrementar a contagem no loop!!
print("Done")
Saída:
$ python infinite.py
contagem: 0
contagem: 0
contagem: 0
contagem: 0
contagem: 0
contagem: 0
contagem: 0
contagemcontagem: 0
...
...
O que fez com que a condição seja sempre
Verdadeira
? A condição que incrementa a contagem está faltando, então sempre será inferior a 5. Para impedir o código de imprimir para sempre utilize ctrl+c. Um comportamento como esse é quase sempre devido a um bug no código.
Uma forma melhor de escrever um loop infinito é com True
. Você precisará incluir algo como if ...: break
#!/usr/bin/env python3
contagem=0
while True:
print("contagem:",contagem)
# Provavelmente você precisará adicionar um "if...: break"
# para poder sair do loop infinito
print('Finished the loop')
Um for loop é um loop que executa o bloco de códigos for para qualquer membro de uma sequência, por exemplo os elementos de uma lista ou as letras de uma string.
for iterating_variable in sequence:
statement(s)
Um exemplo de sequência é uma lista. Vamos usar um for loop com uma lista de palavras.
Código:
#!/usr/bin/env python3
words = ['zero','um','dois','três','quatro']
for word in words:
print(word)
Perceba como eu nomeei minhas variáveis, a lista é plural e a variável interativa é singular
Saída:
python3 list_words.py
zero
um
dois
três
quatro
Esse próximo exemplo é utilizando um for loop para iterar em uma string. Lembre-se que uma string é uma sequência como uma lista. Cada caractere possui uma posição. Olhe novamente em "Extraindo uma substring, ou Recortando" na seção Strings para ver outras formas em que strings podem ser tratadas como listas.
Código:
#!/usr/bin/env python3
dna = 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA'
for nt in dna:
print(nt)
Saída:
$ python3 for_string.py
G
T
A
C
C
T
T
...
...
Essa é uma forma fácil de acessar cada caractere em uma string. É especialmente bom para sequências de DNA.
Outro exemplo de iterar em uma lista de variáveis, estes números de tempo.
Código:
#!/usr/bin/env python3
numbers = [0,1,2,3,4]
for num in numbers:
print(num)
Saída:
$ python3 list_numbers.py
0
1
2
3
4
Python tem uma função chamada range()
que retornará números que podem ser convertidos em uma lista.
>>> range(5)
range(0, 5)
>>> list(range(5))
[0, 1, 2, 3, 4]
A função range()
pode ser utilizada em conjunto com um for loop para iterar em um faixa de números. A função range()
também começa com 0 e opera sobre os espaços entre os números.
Código:
#!/usr/bin/env python3
for num in range(5):
print(num)
Saída:
$ python list_range.py
0
1
2
3
4
Como pode ver esta é a mesma saída que quando utilizamos a lista
numbers = [0, 1, 2, 3, 4]
E esse tem a mesma funcionalidade que um while loop com a condiçãocount = 0
;count < 5
.
Esse é o while loop equivalente
Código:
count = 0
while count < 5:
print(count)
count+=1
Saída:
0
1
2
3
4
As declarações de controle de loop permitem alteração no fluxo normal de execução.
Declaração de controle | Descrição |
---|---|
break |
Um loop é terminado quando uma declaração break é executada. Todas as linhas de código após o break, mas dentro do bloco de loop, não são executadas. Sem mais interações do loop sendo executadas |
continue |
Uma única iteração de um loop é terminada quando a declaração continue é executada. A próxima iteração vai proceder normalmente. |
Código:
#!/usr/bin/env python3
count = 0
while count < 5:
print("count:" , count)
count+=1
if count == 3:
break
print("Done")
Saída:
$ python break.py
count: 0
count: 1
count: 2
Done
Quando a contagem é igual a 3, a execução do while loop é terminada, no entanto a condição inicial permanece verdadeira (count < 5).
Código:
#!/usr/bin/env python3
count = 0
while count < 5:
print("count:" , count)
count+=1
if count == 3:
continue
print("Linha após o nosso continue")
print("Done")
Saída:
$ python continue.py
count: 0
Linha após o nosso continue
count: 1
Linha após o nosso continue
count: 2
count: 3
Linha após o nosso continue
count: 4
Linha após o nosso continue
Done
Quando a contagem é igual a 3 o continue é executado. Isso faz com que todas as linhas contendo o bloco de loop sejam puladas. "Linha após o nosso continue" não é impresso quando a contagem é igual a 3. O próximo loop é executado normalmente.
Um iterável é qualquer tipo de dado que pode ser iterado, ou pode ser usado em uma iteração. Um iterável pode ser transformado em um iterador com a função iter()
. Isso significa que você pode utilizar a função next()
.
>>> codons = [ 'atg' , 'aaa' , 'agg' ]
>>> codons_iterator=iter(codons)
>>> next(codons_iterator)
'atg'
>>> next(codons_iterator)
'aaa'
>>> next(codons_iterator)
'agg'
>>> next(codons_iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Um iterador permite que você obtenha o próximo elemento no iterador até que não existam mais elementos. Se você quer ir através de cada elemento novamente, você precisará redefinir o iterador.
Exemplo de utilização de um iterador em um for loop:
codons = [ 'atg' , 'aaa' , 'agg' ]
>>> codons_it = iter(codons)
>>> for codon in codons_it :
... print( codon )
...
atg
aaa
agg
Isso é bom se você tem uma lista muito larga que você não deseja manter na memória. Um iterador permite que você vá através de cada elemento mas sem manter a lista completa na memória. Sem iteradores toda a lista permanece na memória.
Compreensão de lista é uma forma de fazer uma lista sem digitar cada elemento. Existem muitas formas de usar compreensão de lista para gerar listas. Alguns são relativamente complexos, mas úteis.
Aqui está um exemplo fácil:
>>> dna_list = ['TAGC', 'ACGTATGC', 'ATG', 'ACGGCTAG']
>>> lengths = [len(dna) for dna in dna_list]
>>> lengths
[4, 8, 3, 8]
Isso é como você pode fazer o mesmo com um for loop:
>>> lengths = []
>>> dna_list = ['TAGC', 'ACGTATGC', 'ATG', 'ACGGCTAG']
>>> for dna in dna_list:
... lengths.append(len(dna))
...
>>> lengths
[4, 8, 3, 8]
Utilizando condições:
Isso vai apenas retornar o comprimento de um elemento que começa com 'A':
>>> dna_list = ['TAGC', 'ACGTATGC', 'ATG', 'ACGGCTAG']
>>> lengths = [len(dna) for dna in dna_list if dna.startswith('A')]
>>> lengths
[8, 3, 8]
Esse gera a seguinte lista: [8, 3, 8]
Aqui está um exemplo de utilização de operadores matemáticos para gerar uma lista:
>>> two_power_list = [2 ** x for x in range(10)]
>>> two_power_list
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
Isso cria uma lista do produto de [2^0 , 2^1, 2^2, 2^3, 2^4, 2^5, 2^6, 2^7, 2^8, 2^9 ]
Dicionários são outra estrutura iterável, semelhante a uma string e uma lista. Ao contrário de strings e listas, os dicionários não são uma sequência, ou em outras palavras, eles são não ordenados e a posição não é importante.
Dicionários são uma coleção de pares chave/valor. Em Python, cada chave é separada de seu valor por dois pontos (:), os itens são separados por vírgulas, e tudo é envolto por chaves. Um dicionário vazio sem itens é escrito apenas com duas chaves, assim: {}
Cada chave em um dicionário é única, enquanto os valores podem não ser. Os valores de um dicionário podem ser de qualquer tipo, mas as chaves devem ser de um tipo de dado imutável, como strings, números ou tuplas.
Dados apropriados para dicionários são duas informações que naturalmente estão relacionadas, como o nome de um gene e sua sequência.
Chave | Valor |
---|---|
TP53 | GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC |
BRCA1 | GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA |
genes = { 'TP53' : 'GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC' , 'BRCA1' : 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA' }
Dividir os pares chave/valor em várias linhas facilita a leitura.
genes = {
'TP53' : 'GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC' ,
'BRCA1' : 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA'
}
Para recuperar um único valor em um dicionário, use a chave do valor neste formato dict[chave]
. Isso retornará o valor na chave especificada.
>>> genes = { 'TP53' : 'GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC' , 'BRCA1' : 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA' }
>>>
>>> genes['TP53']
GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC
A sequência do gene TP53 está armazenada como um valor da chave 'TP53'. Podemos acessar a sequência usando a chave neste formato dict[chave].
O valor pode ser acessado e passado diretamente para uma função ou armazenado em uma variável.
>>> print(genes['TP53'])
GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC
>>>
>>> seq = genes['TP53']
>>> print(seq)
GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC
Lembre-se da lista de culturas e produção acima. Vamos criar um dicionário com esses dados:
>>> producao_por_cultura = {'soja': 3000, 'milho': 8000, 'algodao':2000 , 'arroz':3000}
>>> print(producao_por_cultura['milho'])
Também podemos criar um dicionario com um animal repreentativo de cada bioma brasileiro:
>>> animais_por_bioma={'Amazonia':'Arara-vermelha','Cerrado':'Lobo-guará','Mata Atlantica': 'Capivara','Pantanal': 'Onca','Pampa': 'Garça','Caatinga': 'Jiboia'}
>>> print(animais_por_bioma['Cerrado'])
Valores individuais podem ser alterados usando a chave e o operador de atribuição.
>>> genes = { 'TP53' : 'GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC' , 'BRCA1' : 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA' }
>>>
>>> print(genes)
{'BRCA1': 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA', 'TP53': 'GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC'}
>>>
>>> genes['TP53'] = 'atg'
>>>
>>> print(genes)
{'BRCA1': 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA', 'TP53': 'atg'}
O conteúdo do dicionário foi alterado.
Outros operadores de atribuição também podem ser usados para alterar um valor de uma chave de dicionário.
>>> genes = { 'TP53' : 'GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC' , 'BRCA1' : 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA' }
>>>
>>> genes['TP53'] += 'TAGAGCCACCGTCCAGGGAGCAGGTAGCTGCTGGGCTCCGGGGACACTTTGCGTTCGGGCTGGGAGCGTG'
>>>
>>> print(genes)
{'BRCA1': 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA', 'TP53': 'GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTCTAGAGCCACCGTCCAGGGAGCAGGTAGCTGCTGGGCTCCGGGGACACTTTGCGTTCGGGCTGGGAGCGTG'}
Aqui, usamos o operador de atribuição de concatenação '+='. Isso é equivalente a
genes['TP53'] = genes['TP53'] + 'TAGAGCCACCGTCCAGGGAGCAGGTAGCTGCTGGGCTCCGGGGACACTTTGCGTTCGGGCTGGGAGCGTG'
.
No dicionário de animais dos biomas brasileiros, vamos substituir a Capivara da Mata Atlântica pelo Tucano.
>>> animais_por_bioma['Mata Atlantica']= 'Tucano'
>>> print(animais_por_bioma)
Já que um dicionário é um objeto iterável, podemos percorrer os seus conteúdos.
Um loop for pode ser usado para recuperar cada chave de um dicionário de cada vez:
>>> for gene in genes:
... print(gene)
...
TP53
BRCA1
Depois de obter a chave, você pode recuperar o valor:
>>> for gene in genes:
... seq = genes[gene]
... print(gene, seq[0:10])
...
TP53 GATGGGATTG
BRCA1 GTACCTTGAT
Vamos imprimir os animais representativos dos biomas brasileiros:
>>> for bioma in animais_por_bioma:
... animal=animais_por_bioma[bioma]
... print(bioma, animal)
...
Amazonia Arara-vermelha
Cerrado Lobo-guará
Mata Atlantica Tucano
Pantanal Onca
Pampa Garça
Caatinga Jiboia
Construir um dicionário uma chave/valor de cada vez é semelhante ao que acabamos de ver quando alteramos o valor de uma chave. Normalmente, você não fará isso. Falaremos sobre maneiras de construir um dicionário a partir de um arquivo em uma palestra posterior.
>>> genes = {}
>>> print(genes)
{}
>>> genes['Brca1'] = 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA'
>>> genes['TP53'] = 'GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC'
>>> print(genes)
{'Brca1': 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA', 'TP53': 'GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC'}
Começamos criando um dicionário vazio. Em seguida, adicionamos cada par chave/valor usando a mesma sintaxe que usamos ao alterar um valor.
dict[key] = new_value
Python gera um erro (NameError) se você tentar acessar uma chave que não existe.
>>> print(genes['HDAC'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'HDAC' is not defined
Operador | Descrição |
---|---|
in |
key in dict retorna True se a chave existe no dicionário |
not in |
key not in dict retorna True se a chave não existe no dicionário |
Como o Python gera um NameError se você tentar usar uma chave que não existe no dicionário, é necessário verificar se uma chave existe antes de tentar usá-la.
A melhor maneira de verificar se uma chave existe é usando in
.
>>> gene = 'TP53'
>>> if gene in genes:
... print('found')
...
found
>>>
>>> if gene in genes:
... print(genes[gene])
...
GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC
>>>
Agora temos todas as ferramentas para construir um dicionário com um par de chave/valor usando um loop for. Isso é como você construirá dicionários com mais frequência na vida real.
Aqui, vamos contar e armazenar contagens de nucleotídeos:
#!/usr/bin/env python3
# cria um dicionário vazio
nt_count={}
# exemplo de loop
dna = 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA'
for nt in dna:
# 'nt' está no dicionário?
if nt in nt_count:
# se sim, aumentamos a contagem
previous_count = nt_count[nt]
new_count = previous_count + 1
nt_count[nt] = new_count
else:
# se não, adicionamos e contamos 1
nt_count[nt] = 1;
print(nt_count)
{'G': 20, 'T': 21, 'A': 13, 'C': 16}
Qual outra maneira podemos contar?
nt_count={}
dna = 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA'
for nt in dna:
if nt in nt_count:
nt_count[nt] += 1
else:
nt_count[nt] = 1;
print(nt_count)
lembre-se que
count=count+1
é o mesmo quecount+=1
Se você deseja imprimir o conteúdo de um dicionário, deve classificar as chaves e, em seguida, iterar sobre as chaves com um loop for. Por que você gostaria de classificar as chaves?
for gene_key in sorted(genes): # python permite que você use atalhos em um "for loop"
# você não precisa escrever genes.keys() em um for loop
# para iterar sobre as chaves
print(gene_key, '=>' , genes[gene_key])
Isso imprimirá as chaves na mesma ordem toda vez que você executar seu script. Dicionários são desordenados, então sem ordenação, você obterá uma ordem diferente cada vez que executar o script, o que pode ser confuso.
Função | Descrição |
---|---|
len(dict) |
retorna o número total de pares chave/valor |
str(dict) |
retorna uma representação em string do dicionário |
type(variable) |
Retorna o tipo ou classe da variável passada para a função. Se a variável for um dicionário, ela retornará o tipo "dicionário". |
Essas funções também funcionam com vários outros tipos de dados!
Métodos | Descrição |
---|---|
dict.clear() |
Remove todos os elementos do dicionário dict . |
dict.copy() |
Retorna uma cópia rasa (shallow copy) do dicionário. Shallow vs. deep A cópia só é relevante em estruturas de dados multidimensionais. |
dict.fromkeys(seq,value) |
Crie um novo dicionário com chaves de seq (tipo de sequência Python) e valores definidos como valor. |
dict.items() |
Retorna uma lista de tuplas (chave, valor). |
dict.pop(key) |
Remove o par chave:valor e retorna o valor. |
dict.keys() |
Retorna uma lista de chaves |
dict.get(key, default = None) |
Obtenha o valor de dict[key], use o padrão se não estiver presente. |
dict.setdefault(key, default = None) |
Semelhante a get(), mas definirá dict[key] = default se a chave ainda não estiver em dict. |
dict.update(dict2) |
Adiciona os pares chave-valor do dicionário dict2 ao dicionário dict. |
dict.values() |
Retorna uma lista dos valores do dicionário dict . |
Um conjunto é outro tipo de dado em Python. Essencialmente, é um dicionário com chaves, mas sem valores.
- Um conjunto é não ordenado.
- Um conjunto é uma coleção de dados sem elementos duplicados.
- Usos comuns incluem buscar diferenças e eliminar duplicatas em conjuntos de dados.
Chaves {}
ou a função set()
podem ser usadas para criar conjuntos.
Observação: para criar um conjunto vazio, você precisa usar
set()
, não{}
, este último cria um dicionário vazio.
>>> basket = {'maçã', 'laranja', 'maçã', 'pera', 'laranja', 'banana'}
>>> print(basket)
{'laranja', 'banana', 'pera', 'maçã'}
Veja, os duplicados foram removidos.
Testar se um valor está no conjunto.
>>> 'laranja' in basket
True
>>> 'capim-colchão' in basket
False
O operador
in
funciona da mesma forma com conjuntos como funciona com listas e dicionários.
União, interseção, diferença e diferença simétrica podem ser feitas com conjuntos.
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a
{'a', 'r', 'b', 'c', 'd'}
Conjuntos contêm elementos únicos; portanto, mesmo que elementos duplicados sejam fornecidos, eles serão removidos.
Diferença
A diferença entre dois conjuntos são os elementos que são exclusivos do conjunto à esquerda do operador -
, com duplicatas removidas..
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a - b
{'r', 'd', 'b'}
Isso resulta nas letras que estão em "a", mas não em "b".
União
A união entre dois conjuntos é uma sequência de todos os elementos de ambos os conjuntos combinados, com duplicatas removidas.
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a | b
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
Isso retorna as letras que estão em ambos os conjuntos a e b.
Interseção
A interseção entre dois conjuntos é uma sequência dos elementos que estão em ambos os conjuntos ao mesmo tempo, com duplicatas removidas.
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a & b
{'a', 'c'}
Isso retorna as letras que estão em ambos os conjuntos
a
eb
.
Diferença simétrica
A diferença simétrica é composta pelos elementos que estão apenas no primeiro conjunto, mais os elementos que estão apenas no segundo conjunto, com duplicatas removidas.
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a ^ b
{'r', 'd', 'b', 'm', 'z', 'l'}
Isso retorna as letras que estão em
a
oub
, mas não em ambos (também conhecido como ou exclusivo).
Funções | Descrição |
---|---|
all() |
retorna True se todos os elementos do conjunto forem True (ou se o conjunto estiver vazio). |
any() |
retorna True se algum elemento do conjunto for True . Se o conjunto estiver vazio, retorna False . |
enumerate() |
retorna um objeto enumerate . Ele contém o índice e o valor de todos os itens do conjunto como um par. |
len() |
retorna o número de itens no conjunto. |
max() |
retorna o maior item no conjunto. |
min() |
retorna o menor item no conjunto. |
sorted() |
retorna uma nova lista ordenada a partir dos elementos no conjunto (não altera o conjunto original). |
sum() |
retorna a soma de todos os elementos no conjunto. |
Métodos | Descrição |
---|---|
set.add(new) |
adiciona novos elementos |
set.clear() |
remove todos elementos |
set.copy() |
retorna uma cópia rasa de um conjunto |
set.difference(set2) |
retorna a diferença entre o set e o set2 |
set.difference_update(set2) |
remove todos os elementos de outro conjunto (set) deste conjunto (set2) |
set.discard(element) |
remove um elemento do conjunto se ele for encontrado no conjunto. (Não faz nada se o elemento não estiver no conjunto) |
set.intersection(sets) |
retorna a interseção do conjunto com outros conjuntos fornecidos |
set.intersection_update(sets) |
atualiza o conjunto com a interseção do conjunto (set) e os outros conjuntos fornecidos (sets). |
set.isdisjoint(set2) |
retorna Verdadeiro se o set e o set2 não têm interseção. |
set.issubset(set2) |
retorna Verdadeiro se o set2 contém o conjunto. |
set.issuperset(set2) |
retorna Verdadeiro se o set contém o set2. |
set.pop() |
remove e retorna um elemento arbitrário do conjunto. |
set.remove(element) |
remove um elemento de um conjunto. |
set.symmetric_difference(set2) |
retorna a diferença simétrica entre o set e o set2. |
set.symmetric_difference_update(set2) |
atualiza o conjunto com a diferença simétrica entre o set e o set2 |
set.union(sets) |
retorna a união do conjunto (set) e dos outros conjuntos fornecidos (sets). |
set.update(set2) |
atualiza o conjunto com a união do set e o set2. |
Vamos dar uma reviravolta no nosso script de contagem de NT. Vamos usar um conjunto para encontrar todos os NTs únicos e, em seguida, usar o método count()
da string para contar o nucleotídeo, em vez de incrementar a contagem como fizemos anteriormente.
Código:
#!/usr/bin/env python3
# crie um novo dicionário
nt_count = {}
# obtenha um conjunto de caracteres únicos em nossa sequência de DNA.
dna = 'GTACCNTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA'
unique = set(dna)
print('unique nt: ', unique) ## {'C', 'A', 'G', 'T', 'N'}
# Itere através de cada nucleotídeo único.
for nt in unique:
# Conte o número deste nucleotídeo único no DNA.
count = dna.count(nt)
# Adicione nossa contagem ao nosso dicionário.
nt_count[nt] = count
print('nt count:', nt_count)
Output:
unique nt: {'N', 'C', 'T', 'G', 'A'}
nt count: {'G': 20, 'T': 21, 'A': 13, 'C': 16, 'N': 1}
Temos a contagem para todos os NTs, até mesmo aqueles que talvez não esperássemos.
I/O significa input/output. O "in" e "out" referem-se a obter dados dentro e fora do seu script. Pode ser um pouco surpreendente no início, mas escrever na tela, ler do teclado, ler de um arquivo e escrever em um arquivo são todos exemplos de I/O.
Você deve estar bem familiarizado com a escrita na tela. Temos usado a função print()
para isso.
>>> print ("Olá, PFB2019!")
Olá, PFB2019!
Lembra-se desse exemplo de uma das nossas primeiras lições?
Isso é algo novo. Há uma função que imprime uma mensagem na tela e espera uma entrada do teclado. Essa entrada pode ser armazenada em uma variável. Ela sempre começa como uma string. Converta para int ou float se quiser um número. Quando terminar de digitar o texto, pressione a tecla Enter para encerrar a entrada. Um caractere de nova linha não está incluído na entrada.
>>> user_input = input("Digite algo agora: ")
Digite algo agora: Oi
>>> print(user_input)
Oi
>>> type(user_input)
<class 'str'>
A maioria dos dados com os quais lidaremos estará contida em arquivos.
O primeiro passo com um arquivo é abri-lo. Podemos fazer isso com a função open()
. A função open()
leva o nome do arquivo e o modo de acesso como argumentos e retorna um objeto de arquivo.
Os modos de acesso mais comuns são leitura (r) e escrita (w).
>>> objeto_arquivo = open("seq.nt.txt", "r")
'objeto_arquivo' é o nome de uma variável. Pode ser qualquer coisa, mas faça um nome útil que descreva que tipo de arquivo você está abrindo.
Agora que abrimos um arquivo e criamos um objeto de arquivo, podemos fazer coisas com ele, como ler. Vamos ler todo o conteúdo de uma vez.
Vamos para a linha de comando e use cat
para ver o conteúdo do arquivo primeiro.
$ cat seq.nt.txt
ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAG
ACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG
$
Observe as novas linhas. Agora, vamos imprimir o conteúdo na tela com Python. Vamos usar read()
para ler todo o conteúdo do arquivo em uma variável.
>>> arquivo = open("seq.nt.txt", "r")
>>> conteudo = arquivo.read()
>>> print(conteudo) # observe que os caracteres de nova linha fazem parte do arquivo!
ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAG
ACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG
>>> arquivo.close()
O conteúdo completo pode ser obtido com o método
read()
. Observe que as novas linhas são mantidas quando oconteudo
é impresso na tela.print()
adiciona outra nova linha quando termina de imprimir. É uma boa prática fechar seu arquivo. Use o métodoclose()
.
Aqui está outra maneira de ler dados de um arquivo. Um loop for
pode ser usado para iterar pelo arquivo uma linha de cada vez.
#!/usr/bin/env python3
arquivo = open("seq.nt.txt", "r")
for linha in arquivo: # Magia do Python: lê uma linha do arquivo
print(linha)
Output:
$ python3 file_for.py
ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAG
ACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG
Observe a linha em branco após cada linha que imprimimos.
print()
adiciona uma nova linha e temos uma nova linha no final de cada linha em nosso arquivo. Use o métodorstrip()
para remover a nova linha de cada linha.
Vamos usar o método rstrip()
para remover a nova linha da entrada do nosso arquivo.
$ cat arquivo_for_rstrip.py
#!/usr/bin/env python3
arquivo_objeto = open("seq.nt.txt", "r")
for linha in arquivo_objeto:
linha = linha.rstrip()
print(linha)
rstrip()
sem nenhum parâmetro retorna uma string com espaços em branco removidos do final.
Output:
$ python3 file_for_rstrip.py
ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAG
ACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG
De onde vêm as novas linhas na saída acima?
Muitas pessoas adicionam isso porque ele fecha o arquivo automaticamente para você. Boa prática de programação. Seu código se limpará conforme ele é executado. Para codificação mais avançada, with ... as ...
economiza recursos limitados, como identificadores de arquivo e conexões de banco de dados. Por enquanto, só precisamos saber que with ... as ...:
faz o mesmo que fh = open(...) ... fh.close()
. Portanto, aqui está como o código adaptado se parece:
#!/usr/bin/env python3
with open("seq.nt.txt", "r") as objeto_arquivo: # limpa após sair do bloco 'with'
for linha in objeto_arquivo:
linha = linha.rstrip()
print(linha)
# o arquivo é fechado para você aqui.
Escrever em um arquivo requer apenas abrir um arquivo para escrita e depois usar o método write()
.
O método write()
é como a função print()
. A maior diferença é que ele escreve no objeto do seu arquivo em vez da tela. Ao contrário do print()
, ele não adiciona uma nova linha por padrão. write()
recebe um único argumento de string.
Vamos escrever algumas linhas em um arquivo chamado "writing.txt".
#!/usr/bin/env python3
fo = open("writing.txt", "w")
fo.write("Uma linha.\n")
fo.write("Segunda linha.\n")
fo.write("Terceira linha" + " tem texto adicional\n")
alguma_var = 5
fo.write("Quarta linha tem " + str(alguma_var) + " palavras\n")
fo.close()
print("Escrito no arquivo 'writing.txt'") # é legal informar ao usuário que você escreveu um arquivo
Output:
$ python3 file_write.py
Escrito no arquivo 'writing.txt'
$ cat writing.txt
Uma linha.
Segunda linha.
Terceira linha tem texto adicional
Quarta linha tem 5 palavras
Agora, vamos ficar loucos! Vamos ler de um arquivo uma linha de cada vez. Faça algo com cada linha e escreva os resultados em um novo arquivo.
#!/usr/bin/env python3
total_nts = 0
# abre dois objetos de arquivo, um para leitura e outro para escrita
with open("seq.nt.txt", "r") as seq_read, open("nt.counts.txt", "w") as seq_write:
for linha in seq_read:
linha = linha.rstrip()
contagem_nt = len(linha)
total_nts += contagem_nt
seq_write.write(str(contagem_nt) + "\n")
seq_write.write("Total: " + str(total_nts) + "\n")
print("Escrito 'nt.counts.txt'")
Output:
$ python3 file_read_write.py
$ cat nt.counts.txt
71
71
Total: 142
O arquivo do qual estamos lendo é chamado de "seq.nt.txt" O arquivo para o qual estamos escrevendo é chamado de "nt.counts.txt" Lemos cada linha, calculamos o comprimento de cada linha e imprimimos o comprimento Também criamos uma variável para acompanhar a contagem total de nt No final, imprimimos o total de nt Finalmente, fechamos cada um dos arquivos
Esta é uma tarefa muito comum. Ela usará um loop, E/S de arquivo e um dicionário.
Suponha que temos um arquivo chamado "sequence_data.txt" que contém nomes de genes e sequências delimitadas por tabulação, que se parece com isto:
TP53 GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC
BRCA1 GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA
Como podemos ler todo este arquivo em um dicionário?
#!/usr/bin/env python3
genes = {}
with open("sequence_data.txt", "r") as seq_read:
for linha in seq_read:
linha = linha.rstrip()
gene_id, seq = linha.split() # dividir no espaço em branco
genes[gene_id] = seq
print(genes)
Output:
{'TP53': 'GATGGGATTGGGGTTTTCCCCTCCCATGTGCTCAAGACTGGCGCTAAAAGTTTTGAGCTTCTCAAAAGTC', 'BRCA1': 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCTTAGCGGTAGCCCCTTGGTTTCCGTGGCAACGGAAAA'}
Expressões regulares são uma linguagem para correspondência de padrões. Muitas linguagens de programação diferentes incorporam expressões regulares, assim como alguns comandos Unix, como grep e sed. Até agora, vimos algumas funções para encontrar correspondências exatas em strings, mas isso nem sempre é suficiente.
Funções que utilizam expressões regulares permitem a correspondência de padrões não exatos.
Essas funções especializadas não estão incluídas no núcleo do Python. Precisamos importá-las digitando
import re
no topo do seu script
#!/usr/bin/env python3
import re
Primeiro, veremos alguns exemplos e depois entraremos nos detalhes mecânicos com mais detalhes.
Vamos começar com algo simples e encontrar uma correspondência exata para o sítio de restrição EcoRI em uma string.
>>> dna = 'ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG'
>>> if re.search(r"GAATTC",dna):
... print("Um sítio de EcoRI foi encontrado!")
...
Um sítio de EcoRI foi encontrado!
>>>
Como podemos pesquisar por caracteres de controle como um tab (\t), é bom criar o hábito de usar a função de string raw
r
ao definir padrões.
Aqui usamos a função
search()
com dois argumentos, 1) nosso padrão e 2) a string que queremos pesquisar.
Vamos descobrir o que é retornado pela função search()
.
>>> dna = 'ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG'
>>> found=re.search(r"GAATTC",dna)
>>> print(found)
<_sre.SRE_Match object; span=(70, 76), match='GAATTC'>
As informações sobre a primeira correspondência são retornadas
E uma correspondência não exata? Vamos procurar por um sítio de metilação que deve corresponder aos seguintes critérios:
- G ou A
- seguido por C
- seguido por qualquer coisa ou nada
- seguido por um G
Isso pode corresponder a qualquer um destes:
- GCAG
- GCTG
- GCGG
- GCCG
- GCG
- ACAG
- ACTG
- ACGG
- ACCG
- ACG
Podemos testar cada um desses ou usar expressões regulares. É exatamente isso que as expressões regulares podem fazer por nós.
>>> dna = 'ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG'
>>> found=re.search(r"[GA]C.?G",dna)
>>> print(found)
<_sre.SRE_Match object; span=(7, 10), match='ACG'>
Aqui você pode ver nas informações retornadas que ACG começa na posição da string 7 (nt 8).
A primeira posição após o final da correspondência está na posição da string 10 (nt 11).
E outras correspondências potenciais em nossa string de DNA? Podemos usar a função findall()
para encontrar todas as correspondências.
>>> dna = 'ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG'
>>> found=re.findall(r"[GA]C.?G",dna)
>>> print(found)
['ACG', 'GCTG', 'ACTG', 'ACCG', 'ACAG', 'ACCG', 'ACAG']
findall()
retorna uma lista de todas as partes da string que correspondem ao regex.
Uma contagem rápida de todos os sítios correspondentes pode ser feita contando o comprimento da lista retornada.
>>> len (re.findall(r"[GA]C.?G",dna))
7
Existem 7 sítios de metilação.
Aqui temos outro exemplo de aninhamento.
Chamamos a função
findall()
, procurando todas as correspondências de um sítio de metilação.Esta função retorna uma lista, a lista é passada para a função
len()
, que por sua vez retorna o número de elementos na lista.
-
Se você quiser encontrar apenas a primeira ocorrência de um padrão, que método você usa?
-
Se você quiser encontrar todas as ocorrências de um padrão, que método você usa?
-
Que operador vimos que reportará se uma correspondência exata está em uma sequência (string, lista, etc.)?
-
Que método de string vimos que contará o número de ocorrências de uma correspondência exata em uma string?
Vamos falar um pouco mais sobre todos os novos caracteres que vemos no padrão.
O padrão é composto por átomos. Cada átomo representa UM caractere.
Átomo | Descrição |
---|---|
a-z, A-Z, 0-9 e algumas pontuações | São caracteres comuns que correspondem a si mesmos |
"." | O ponto, ou período. Isso corresponde a qualquer caractere único, exceto a nova linha. |
Um grupo de caracteres que podem ser correspondidos uma vez. Existem algumas classes predefinidas, que são símbolos que significam uma série de caracteres.
Átomo | Descrição |
---|---|
[ ] |
Uma lista entre colchetes de caracteres, como [GA] . Isso indica que um único caractere pode corresponder a qualquer caractere na lista entre colchetes. |
\d |
Dígitos. Também pode ser escrito como [0-9] |
\D |
Não dígitos. Também pode ser escrito como [^0-9] |
\w |
Caractere de palavra. Também pode ser escrito como [A-Za-z0-9_] . Note que o sublinhado faz parte dessa classe |
\W |
Não é um caractere de palavra, ou [^A-Za-z0-9_] |
\s |
Caractere de espaço em branco. Também pode ser escrito como [ \r\t\n] . Note o caractere de espaço após o primeiro [ |
\S |
Não é um espaço em branco. Também pode ser escrito como [^ \r\t\n] |
[^] |
Um acento circunflexo dentro de uma lista entre colchetes de caracteres indica qualquer coisa, exceto os caracteres que o seguem |
Um padrão pode ser ancorado a uma região na string:
Átomo | Descrição |
---|---|
^ |
Corresponde ao início da string |
$ |
Corresponde ao final da string |
\b |
Corresponde a um limite de palavra entre \w e \W |
Exemplos:
c...a
corresponde a "cobra", "cabra" e "caçar uma cabra" (duas vezes)
\d\d\d-\d\d\d\d
corresponde a 867-5309 e 5867-5309, mas não a 8-67-5309.
^\d\d\d-\d\d\d\d
corresponde a 867-5309 e 867-53091, mas não a 5867-5309.
^\d\d\d-\d\d\d\d$
corresponde apenas a 3 dígitos seguidos de um traço seguido de 4 dígitos, nenhum caractere extra é permitido em qualquer lugar
Os quantificadores quantificam quantos átomos devem ser encontrados. Por padrão, um átomo corresponde apenas uma vez. Esse comportamento pode ser modificado seguindo um átomo com um quantificador.
Quantificador | Descrição |
---|---|
? |
o átomo corresponde zero ou exatamente uma vez |
* |
o átomo corresponde zero ou mais vezes |
+ |
o átomo corresponde uma ou mais vezes |
{3} |
o átomo corresponde exatamente 3 vezes |
{2,4} |
o átomo corresponde entre 2 e 4 vezes, inclusive |
{4,} |
o átomo corresponde pelo menos 4 vezes |
Exemplos:
ca?bra
corresponde a "cabra" e "cbra". Também qualquer texto que contenha essas palavras.
c.+a
corresponde a "cabra", "cobra" e "covabra", entre outros.
c.*a
corresponde a "ca", "cabra", "ceeba" e "covabra", entre outros.
^\d{3}-\d{4}$
corresponde a números de telefone dos EUA (nenhum texto extra é permitido).
- Qual seria um padrão para reconhecer um endereço de e-mail?
- Qual seria um padrão para reconhecer a parte de ID de um registro de sequência em um arquivo FASTA?
Variáveis podem ser usadas para armazenar padrões.
>>> padrao = r"[GA]C.?G"
>>> len(re.findall(padrao, dna))
7
Neste exemplo, armazenamos nosso padrão de metilação na variável chamada 'padrao' e a utilizamos como primeiro argumento para
findall
.
Um pipe '|' pode ser usado para indicar que o padrão antes ou depois do '|' pode ser correspondido. Coloque as duas opções entre parênteses.
grande (lobo|porquinho) mau
Este padrão deve corresponder a uma string que contém:
- "grande" seguido de um espaço seguido por
- ou "lobo" ou "porquinho" seguido de
- um espaço seguido de
- "mau"
Isso corresponderia a:
- "grande lobo mau"
- "grande porquinho mau"
- Qual seria um padrão para reconhecer 'ATG' seguido de C ou um T?
Subpadrões, ou partes do padrão contidas entre parênteses, podem ser extraídos e armazenados para uso posterior.
Quem tem medo do grande mau lobo(.+)f
Este padrão possui apenas um subpadrão (.+)
Você pode combinar parênteses e quantificadores para quantificar subpadrões inteiros.
Quem tem medo do grande (mau )?lobo\?
Isto corresponde a:
- "Quem tem medo do grande mau lobo?"
- Bem como "Quem tem medo do grande lobo?".
O 'mau ' é opcional, ele pode estar presente 0 ou 1 vez em nossa string.
Isso também mostra como corresponder literalmente a caracteres especiais. Use um '\' para escapá-los.
- Que padrão você usaria para capturar o ID em um registro de sequência de um arquivo FASTA em um subpadrão.
Exemplo de registro de sequência FASTA.
>ID Descrição Opcional
SEQUÊNCIA
SEQUÊNCIA
SEQUÊNCIA
Isso é útil quando você deseja encontrar um subpadrão e, em seguida, corresponder ao conteúdo novamente. Eles podem ser usados dentro da chamada da função e depois dela.
Subpadrões dentro da chamada da função
Uma vez que um subpadrão corresponde, você pode se referir a ele dentro da mesma expressão regular. O primeiro subpadrão se torna \1, o segundo \2, o terceiro \3 e assim por diante.
Quem tem medo do l(.)b\1 mau
Isso corresponderia a:
- "Quem tem medo do lobo mau"
- "Quem tem medo do laba mau"
- "Quem tem medo do lebe mau"
Mas não a:
- "Quem tem medo do loba mau"
- "Quem tem medo do labe mau"
Da mesma forma,
\b(\w+)s adoram comida de \1
Este padrão irá corresponder a:
- "cachorros adoram comida de cachorro"
- Mas não a "cachorros adoram comida de macaco".
Fomos capazes de usar o subpadrão dentro da expressão regular usando
\1
Se houvesse mais subpadrões, eles seriam
\2
,\3
,\4
, etc.
Os subpadrões podem ser recuperados após a chamada da função search()
, ou fora da expressão regular, usando o método group()
. Este é um método e pertence ao objeto que é retornado pela função search()
.
Os subpadrões são recuperados por um número. Este será o mesmo número que poderia ser usado dentro da expressão regular, ou seja,
\1
dentro do subpadrão pode ser usado fora comsearch_found_obj.group(1)
\2
dentro do subpadrão pode ser usado fora comsearch_found_obj.group(2)
\3
dentro do subpadrão pode ser usado fora comsearch_found_obj.group(3)
- e assim por diante
Example:
>>> dna = 'ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGATATTATCCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG'
>>> found=re.search( r"(.{50})TATTAT(.{25})" , dna )
>>> upstream = found.group(1)
>>> print(upstream)
TCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGA
>>> downstream = found.group(2)
>> print(downstream)
CCGGTTTCCAAAGACAGTCTTCTAA
- Este padrão reconhecerá um sítio de início de transcrição de consenso (TATTAT)
- E armazenará os 50 pares de bases a montante do sítio
- E os 25 pares de bases a jusante do sítio
Se você quiser encontrar as sequências a montante e a jusante de TODOS os sítios 'TATTAT', use a função findall()
.
>>> dna="ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGATATTATCCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGATATTATCCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG"
>>> found = re.findall( r"(.{50})TATTAT(.{25})" , dna )
>>> print(found)
[('TCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGA', 'CCGGTTTCCAAAGACAGTCTTCTAA'), ('TCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGA', 'CCGGTTTCCAAAGACAGTCTTCTAA')]
Os subpadrões são armazenados em tuplas dentro de uma lista. Mais sobre esse tipo de estrutura de dados mais tarde.
Outra opção para recuperar os subpadrões a montante e a jusante é colocar o findall()
em um loop for
>>> dna="ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGATATTATCCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGATATTATCCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG"
>>> for (upstream, downstream) in re.findall( r"(.{50})TATTAT(.{25})" , dna ):
... print("upstream:" , upstream)
... print("downstream:" , downstream)
...
upstream: TCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGA
downstream: CCGGTTTCCAAAGACAGTCTTCTAA
upstream: TCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGA
downstream: CCGGTTTCCAAAGACAGTCTTCTAA
- Este código executa a função
findall()
uma vez- Os objetos de tupla são retornados
- Os subpadrões são armazenados nas variáveis a montante e a jusante
- O bloco for é executado
- O
findall()
busca novamente- Uma correspondência é encontrada
- Novos subpadrões são retornados e armazenados nas variáveis a montante e a jusante
- O bloco for de código é executado novamente
- O
findall()
busca novamente, mas nenhuma correspondência é encontrada- O loop for termina
Outra maneira de fazer isso é com um iterador, usando a função finditer()
em um loop for. Isso permite que você não armazene todas as correspondências na memória. finditer()
também permite que você recupere a posição da correspondência.
>>> dna="ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGATATTATCCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGATATTATCCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG"
>>> for match in re.finditer(r"(.{50})TATTAT(.{25})" , dna):
... print("upstream:" , match.group(1))
... print("downstream:" , match.group(2))
...
upstream: TCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGA
downstream: CCGGTTTCCAAAGACAGTCTTCTAA
upstream: TCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGA
downstream: CCGGTTTCCAAAGACAGTCTTCTAA
- Este código executa a função
finditer()
uma vez. - O objeto de correspondência é retornado. Um objeto de correspondência terá todas as informações sobre a correspondência.
- No bloco for, chamamos o método
group()
no primeiro objeto de correspondência retornado. - Imprimimos o primeiro e o segundo subpadrão usando o método
group()
. - A função
finditer()
é executada uma segunda vez e uma correspondência é encontrada. - O segundo objeto de correspondência é retornado.
- Os segundos subpadrões são obtidos do objeto de correspondência usando o método
group()
. - A função
finditer()
é executada novamente, mas não são encontradas correspondências, portanto o loop termina.
O objeto de correspondência contém informações sobre a correspondência que podem ser recuperadas com métodos de correspondência como start()
e end()
#!/usr/bin/env python3
import re
dna="ACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGATATTATCCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGACAAAATACGTTTTGTAAATGTTGTGCTGTTAACACTGCAAATAAACTTGGTAGCAAACACTTCCAAAAGGAATTCACCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGATATTATCCGGTTTCCAAAGACAGTCTTCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGG"
for found in re.finditer(r"(.{50})TATTAT(.{25})" , dna):
whole = found.group(0)
up = found.group(1)
down = found.group(2)
up_start = found.start(1) + 1 # é necessário converter da notação 0 para 1
up_end = found.end(1)
dn_start = found.start(2) + 1
dn_end = found.end(2)
print( whole , up , up_start, up_end , down , dn_start , dn_end , sep="\t" )
podemos usar esses métodos de objeto de correspondência
group()
,start()
,end()
para obter a string, a posição de início e a posição de fim de cada subpadrão.
$ python3 re.finditer.pos.py
TCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGATATTATCCGGTTTCCAAAGACAGTCTTCTAA TCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGA 98 148 CCGGTTTCCAAAGACAGTCTTCTAA 154 179
TCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGATATTATCCGGTTTCCAAAGACAGTCTTCTAA TCTAATTCCTCATTAGTAATAAGTAAAATGTTTATTGTTGTAGCTCTGGA 320 370 CCGGTTTCCAAAGACAGTCTTCTAA 376 401
FYI: A função match()
é outra função de expressão regular que procura padrões. É semelhante à search
, mas ela olha apenas para o início da string em busca do padrão, enquanto search
procura em toda a string. Geralmente, finditer()
, search()
e findall()
serão mais úteis.
Por padrão, as expressões regulares são "gananciosas". Elas tentam corresponder o máximo possível. Use o quantificador '?' para tornar a correspondência não gananciosa. A correspondência não gananciosa é chamada de 'preguiçosa'
>>> str = 'The fox ate my box of doughnuts'
>>> found = re.search(r"(f.+x)",str)
>>> print(found.group(1))
fox ate my box
O padrão f.+x não corresponde ao que você pode esperar, ele corresponde a partir de 'fox' até 'fox ate my box'. O '.+' é ganancioso. Ele encontra o máximo possível de caracteres entre 'f' e 'x'.
Vamos tornar essa correspondência preguiçosa usando '?'
>>> found = re.search(r"(f.+?x)",str)
>>> print(found.group(1))
fox
A correspondência agora é preguiçosa e corresponderá apenas a 'fox'
>>> str = 'Atrás da porta torta tem uma porca morta'
>>> found = re.search(r"(p.+a)",str)
>>> print(found.group(1))
porta torta tem uma porca morta
O padrão p.+a não corresponde ao que você pode esperar, ele corresponde a partir de 'porta' até 'porta torta tem uma porca morta'. O '.+' é ganancioso. Ele encontra o máximo possível de caracteres entre 'p' e 'a'.
Vamos tornar essa correspondência preguiçosa usando '?'
>>> found = re.search(r"(p.+?a)",str)
>>> print(found.group(1))
porta
A correspondência agora é preguiçosa e corresponderá apenas a 'porta'
A extração de códons de uma sequência de DNA pode ser realizada usando um subpadrão em uma função findall()
. Lembre-se de que a função findall()
retornará uma lista das correspondências.
>>> dna = 'GTTGCCTGAAATGGCGGAACCTTGAA'
>>> codons = re.findall(r"(.{3})",dna)
>>> print(codons)
['GTT', 'GCC', 'TGA', 'AAT', 'GGC', 'GGA', 'ACC', 'TTG']
Ou você pode usar um loop for para fazer algo com cada correspondência.
>>> for codon in re.findall(r"(.{3})",dna):
... print(codon)
...
GTT
GCC
TGA
AAT
GGC
GGA
ACC
TTG
>>>
finditer()
também funcionaria neste loop for. Cada códon pode ser acessado usando o métodogroup()
.
As funções search()
, match()
, findall()
e finditer()
podem ser usadas em testes condicionais. Se uma correspondência não for encontrada, uma lista vazia ou 'None' é retornada. Ambos são Falsos.
>>> found=re.search( r"(.{50})TATTATZ(.{25})" , dna )
>>> if found:
... print("encontrado")
... else:
... print("não encontrado")
...
não encontrado
>>> print(found)
None
None é False, então o bloco else é executado
e "não encontrado" é impresso.
Aninhe isso!
>>>
>>> if re.search( r"(.{50})TATTATZ(.{25})" , dna ):
... print("encontrado")
... else:
... print("não encontrado")
...
não encontrado
>>> print(found)
None
Anteriormente, vimos como encontrar um padrão exato e substituí-lo usando o método replace()
. Para encontrar um padrão, ou correspondência inexata, e fazer uma substituição, é usada a função de expressão regular sub()
. Esta função recebe o padrão, a substituição, a string a ser pesquisada, o número de vezes que a substituição deve ser feita e as flags.
>>> str = "Quem tem medo do lobo mau?"
>>> re.sub(r'l.+o' , 'porquinho', str)
"Quem tem medo do porquinho mau?"
>>> print(str)
Quem tem medo do lobo mau?
A função
sub()
retorna "Quem tem medo do porquinho mau?" O valor da variávelstr
não foi alterado A nova string pode ser armazenada em uma nova variável para uso posterior.
Vamos salvar a nova string que é retornada em uma variável
>>> str = "Ele tinha uma noiva."
>>> new_str = re.sub(r'n.+i' , 'cabra', str)
>>> print(new_str)
Ele tinha uma cabrava.
>>> print(str)
Ele tinha uma noiva.
Os caracteres entre 'n' e 'i' foram substituídos por 'cabra'. A nova string é salva em
new_str
Às vezes, você deseja encontrar um padrão e usá-lo na substituição.
>>> str = "Quem tem medo do lobo mau?"
>>> new_str = re.sub(r" do (\w+) (\w+)" , r" do \2 \1" , str)
>>> print(new_str)
Quem tem medo do mau lobo?
Encontramos duas palavras depois de 'do' e trocamos a ordem. \2 refere-se ao segundo subpadrão \1 refere-se ao primeiro subpadrão
- Como você usaria expressões regulares para encontrar todas as ocorrências de 'ATG' e substituir por '-M-' nesta sequência 'GCAGAGGTGATGGACTCCGTAATGGCCAAATGACACGT'?
Modificador | Descrição |
---|---|
re.I re.IGNORECASE |
Executa correspondência sem diferenciação entre maiúsculas e minúsculas. |
re.M re.MULTILINE |
Faz com que $ corresponda ao final de uma linha (não apenas ao final da string) e faz com que ^ corresponda ao início de qualquer linha (não apenas ao início da string). |
re.S re.DOTALL |
Faz com que um ponto (.) corresponda a qualquer caractere, incluindo uma nova linha. |
re.U |
Interpreta letras de acordo com o conjunto de caracteres Unicode. Esta bandeira afeta o comportamento de \w, \W, \b, \B. |
re.X VERBOSE |
Essa bandeira permite que você escreva expressões regulares que parecem mais bonitas e sejam mais legíveis, permitindo separar visualmente seções lógicas do padrão e adicionar comentários. Os espaços em branco dentro do padrão são ignorados, exceto quando estão em uma classe de caracteres ou quando precedidos por uma barra invertida não escapada. Quando uma linha contém um # que não está em uma classe de caracteres e não é precedido por uma barra invertida não escapada, todos os caracteres do # mais à esquerda até o final da linha são ignorados. |
>>> dna = "atgcgtaatggc"
>>> re.search(r"ATG",dna)
>>>
>>> re.search(r"ATG",dna , re.I)
<_sre.SRE_Match object; span=(0, 3), match='atg'>
>>>
Podemos tornar nossa pesquisa insensível a maiúsculas e minúsculas usando a bandeira
re.I
oure.IGNORECASE
.
Você pode usar mais de uma bandeira concatenando-as com |
. re.search(r"ATG",dna , re.I|re.M)
Existem muitas ferramentas online para realmente ver o que está acontecendo em sua expressão regular. Procure por Python Regular Expression Tester
Às vezes, uma lista ou dicionário simples simplesmente não faz o que você quer. Às vezes, é necessário organizar dados de maneira mais complexa. Você pode aninhar qualquer tipo de dado dentro de qualquer outro tipo. Isso permite que você construa facilmente tabelas de dados multidimensionais.
Listas de listas, frequentemente chamadas de matrizes, são importantes para organizar e acessar dados.
Aqui está uma maneira de criar uma tabela 3 x 3 de valores.
>>> M = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> M[1] # segunda linha (começa com índice 0)
[4, 5, 6]
>>> M[1][2] # segunda linha, terceiro elemento
6
Aqui está uma maneira de armazenar dados de alinhamento de sequência:
Quatro sequências alinhadas:
AT-TG
AATAG
T-TTG
AA-TA
O alinhamento em uma lista de listas.
aln = [
['A', 'T', '-', 'T', 'G'],
['A', 'A', 'T', 'A', 'G'],
['T', '-', 'T', 'T', 'G'],
['A', 'A', '-', 'T', 'A']
]
Obtenha o comprimento total de uma sequência:
>>> seq = aln[2]
>>> seq
['T', '-', 'T', 'T', 'G']
Use o índice mais externo para acessar cada sequência.
Recupere o nucleotídeo em uma posição específica em uma sequência.
>>> nt = aln[2][3]
>>> nt
'T'
Use o índice mais externo para acessar a sequência de interesse e o índice mais interno para acessar a posição.
Obtenha todos os nucleotídeos em uma única coluna:
>>> col = [seq[3] for seq in aln]
>>> col
['T', 'A', 'T', 'T']
Recupere cada sequência da lista
aln
e, em seguida, a quarta coluna para cada sequência.
Você também pode aninhar dicionários em listas:
>>> records = [
... {'seq': 'actgctagt', 'accession': 'ABC123', 'genetic_code': 1},
... {'seq': 'ttaggttta', 'accession': 'XYZ456', 'genetic_code': 1},
... {'seq': 'cgcgatcgt', 'accession': 'HIJ789', 'genetic_code': 5}
... ]
>>> records[0]['seq']
'actgctagt'
>>> records[0]['accession']
'ABC123'
>>> records[0]['genetic_code']
1
Aqui você pode recuperar o acesso de um registro por vez usando uma combinação do índice externo e a chave 'accession'.
E, se você não adivinhou, você pode aninhar listas em dicionários.
Aqui está um dicionário de kmers. A chave é o kmer e seus valores são uma lista de posições.
>>> kmers = {'ggaa': [4, 10], 'aatt': [0, 6, 12], 'gaat': [5, 11], 'tgga': [3, 9], 'attg': [1, 7, 13], 'ttgg': [2, 8]}
>>> kmers
{'tgga': [3, 9], 'ttgg': [2, 8], 'aatt': [0, 6, 12], 'attg': [1, 7, 13], 'ggaa': [4, 10], 'gaat': [5, 11]}
>>>
>>> kmers['ggaa']
[4, 10]
>>> len(kmers['ggaa'])
2
Aqui, podemos obter uma lista das posições de um kmer usando o kmer como chave. Também podemos fazer coisas com a lista retornada, como determinar seu comprimento. O comprimento será o total de contagens desse kmer.
Você também pode usar o método get()
para recuperar registros.
>>> kmers['ggaa']
[4, 10]
>>> kmers.get('ggaa')
[4, 10]
Essas duas declarações retornam os mesmos resultados, mas se a chave não existir, você obterá nada e não um erro.
Dicionários de dicionários são os meus favoritos!! Você pode fazer tantas coisas úteis com essa estrutura de dados. Aqui estamos armazenando um nome de gene e alguns tipos diferentes de informações sobre esse gene, como sua sequência, comprimento, descrição, composição de nucleotídeos e comprimento.
>>> genes = {
... 'gene1' : {
... 'seq' : "TATGCC",
... 'desc' : 'something',
... 'len' : 6,
... 'nt_comp' : {
... 'A' : 1,
... 'T' : 2,
... 'G' : 1,
... 'C' : 2,
... }
... },
...
... 'gene2' : {
... 'seq' : "CAAATG",
... 'desc' : 'something',
... 'len' : 6,
... 'nt_comp' : {
... 'A' : 3,
... 'T' : 1,
... 'G' : 1,
... 'C' : 1,
... }
... }
... }
>>> genes
{'gene1': {'nt_comp': {'C': 2, 'G': 1, 'A': 1, 'T': 2}, 'desc': 'something', 'len': 6, 'seq': 'TATGCC'}, 'gene2': {'nt_comp': {'C': 1, 'G': 1, 'A': 3, 'T': 1}, 'desc': 'something', 'len': 6, 'seq': 'CAAATG'}}
>>> genes['gene2']['nt_comp']
{'C': 1, 'G': 1, 'A': 3, 'T': 1}
Aqui, armazenamos um nome de gene como a chave mais externa, com um segundo nível de chaves para características do gene, como sequência, comprimento, composição de nucleotídeos. Podemos recuperar uma característica usando o nome do gene e a característica em conjunto.
Para recuperar apenas a composição de nucleotídeos de um gene:
>>> genes['gene1']['nt_comp']
{'C': 2, 'G': 1, 'A': 1, 'T': 2}
Altere a contagem de nucleotídeos de um gene com o operador de atribuição =
:
>>> genes['gene1']['nt_comp']
{'C': 2, 'G': 1, 'A': 1, 'T': 2}
>>>
>>> genes['gene1']['nt_comp']['T'] = 6
>>> genes['gene1']['nt_comp']
{'C': 2, 'G': 1, 'A': 1, 'T': 6}
Altere a contagem de nucleotídeos de um gene com o operador de atribuição +=
:
>>> genes['gene1']['nt_comp']
{'C': 2, 'G': 1, 'A': 1, 'T': 6}
>>>
>>> genes['gene1']['nt_comp']['A'] += 1
>>>
>>> genes['gene1']['nt_comp']
{'C': 2, 'G': 1, 'A': 2, 'T': 6}
>>>
>>>
Para recuperar a composição de A de todos os genes, use um loop for.
>>> for gene in sorted(genes):
... A_comp = genes[gene]['nt_comp']['A']
... print(gene + ":", "As =", A_comp)
...
gene1: As= 2
gene2: As= 3
A seguir, um exemplo de construção de uma lista com uma coleção mista de tipos de valores. Lembre-se de que todos os elementos dentro de uma lista ou dicionário devem ser do mesmo tipo. Em outras palavras, os valores em uma lista devem ser todos listas, dicionários ou valores escalares. Isso permite que você faça loop sobre a estrutura de dados.
O dicionário, que é um valor de lista, tem uma chave que tem um dicionário como valor.
[{'gene1' : {'sequence' : [1, 2, 3], [4, 5, 6], [7,8,9]]
Apenas espaçado de maneira diferente:
[
[1, 2, 3],
[4, 5, 6],
{
'key': 'value',
'key2':
{
'something_new': 'Yay'
}
}
]
Construindo esta estrutura de dados no interpretador:
>>> new_data = []
>>> new_data
[]
>>> new_data.append([1, 2, 3])
>>> new_data
[[1, 2, 3]]
>>> new_data[0]
[1, 2, 3]
>>> new_data.append([4, 5, 6])
>>> new_data
[[1, 2, 3], [4, 5, 6]]
>>> new_data[1]
[4, 5, 6]
>>> new_data[1][2]
6
>>> new_data.append({})
>>> new_data
[[1, 2, 3], [4, 5, 6], {}]
>>> new_data[2]['key'] = 'value'
>>> new_data
[[1, 2, 3], [4, 5, 6], {'key': 'value'}]
>>> new_data[2]['key2'] = {}
>>> new_data
[[1, 2, 3], [4, 5, 6], {'key2': {}, 'key': 'value'}]
>>> new_data[2]['key2']['something_new'] = 'Yay'
>>> new_data
[[1, 2, 3], [4, 5, 6], {'key2': {'something_new': 'Yay'}, 'key': 'value'}]
>>>
O mesmo exemplo em um arquivo de script: Building Complex Datastructures
Organização e Contagem de Camisetas do Curso
Temos uma planilha com o estilo, tamanho e cor de todos. Queremos saber quantas de cada combinação única de estilo-tamanho-cor precisamos encomendar.
mens small heather seafoam
womens medium Heather Purple
womens medium berry
mens medium heather coral silk
womens Small Kiwi
Mens large Graphite Heather
mens large sport grey
mens small Carolina Blue
Queremos algo assim:
womens small antique heliconia 2
womens xs heather orange 1
womens medium kiwi 2
womens medium royal heather 1
#!/usr/bin/env python3
shirts = {}
with open("shirts.txt", "r") as file_object:
for line in file_object:
line = line.rstrip()
[style, size, color] = line.split("\t")
style = style.lower()
size = size.lower()
color = color.lower()
if style not in shirts:
shirts[style] = {}
if size not in shirts[style]:
shirts[style][size] = {}
if color not in shirts[style][size]:
shirts[style][size][color] = 0
shirts[style][size][color] += 1
for style in shirts:
for size in shirts[style]:
for color in shirts[style][size]:
count = shirts[style][size][color]
print(style, size, color, count, sep="\t")
Saída:
sro$ python3 shirts.py
mens small heather maroon 1
mens small royal blue 1
mens small olive 1
mens large graphite heather 1
womens medium heather purple 3
womens medium berry 2
womens medium royal heather 1
womens medium kiwi 2
...
É assim que se parece a estrutura de dados que acabamos de construir.
{
'mens':
{
'small':
{
'heather seafoam': 1,
'carolina blue': 1,
'cornsilk': 1,
'dark heather': 1,
'heather maroon': 1,
'royal blue': 1,
'olive': 1
},
'large':
{
'graphite heather': 1,
'sport grey': 1,
'heather purple': 1,
'heather coral silk': 1,
'heather irish': 1,
'heather royal': 1,
'carolina blue': 1
},
'medium':
{
'heather coral silk': 1,
'heather royal': 2,
'heather galapagos blue': 1,
'heather forest': 1,
'gold': 1,
'heather military green': 1,
'dark heather': 1,
'carolina blue': 1,
'iris': 1
},
'xs':
{
'white': 1
},
'xl':
{
'heather cardinal': 1,
'indigo blue': 1
}
},
'womens':
{
'medium':
{
'heather purple': 3,
'berry': 2,
'royal heather': 1,
'kiwi': 2,
'carolina blue': 1
},
'small':
{
'kiwi': 1,
'berry': 1,
'antique heliconia': 2
},
'large':
{
'kiwi': 1
},
'xs':
{
'heather orange': 1
}
},
'child':
{
'4t':
{
'green': 2
},
'3t':
{
'pink': 1
},
'2t':
{
'orange': 1
},
'6t':
{
'pink': 1
}
}
}
Também existem bibliotecas específicas para manipulação de tabelas e quadros de dados, como o Pandas.
Aqui é uma introdução às estruturas de dados no Pandas.
E também há um tutorial interativo
Existem alguns diferentes tipos de erros enquanto estamos programando. Erros de sintaxe, erros de lógica e exceções. Você provavelmente já encontrou todos os três. Erros de sintaxe e lógica são problemas com os quais você precisa lidar enquanto está programando. Uma exceção é um tipo especial de erro que pode ser informativo e usado para escrever códigos para responder a esse tipo de erro. Isso é especialmente relevante ao lidar com a entrada do usuário. E se ele não lhe der nenhuma, ou é o tipo errado de entrada. Nós queremos que nosso código seja capaz de detectar esses tipos de erros e responda adequadamente.
#!/usr/bin/env python3
import sys
file = sys.argv[1]
print("User provided file:" , file)
Este código aceita uma entrada fornecida pelo usuário e a imprime.
Execute-o.
$ python scripts/exceptions.py test.txt
User provided file: test.txt
O que acontece se o usuário não fornecer nenhuma entrada e tentar imprimi-la?
$ python scripts/exceptions.py
Traceback (most recent call last):
File "scripts/exceptions.py", line 4, in <module>
file = sys.argv[1]
IndexError: list index out of range
Obtemos uma exceção IndexError exception, a qual é gerada quando o índice não é encontrado em uma sequência.
Já vimos várias exceções ao longo dos capítulos, aqui estão algumas:
- ValueError: erro de domínio matemático
- AttributeError: o objeto 'list' não tem o atributo 'rstrip'
- SyntaxError: EOL ao analisar a string literal
- NameError: o nome 'GGTCTAC' não está definido
- SyntaxError: parênteses ausentes na chamada para 'print'
- AttributeError: o objeto 'int' não tem atributo 'lower'
- IndexError: índice de atribuição de lista fora de alcance
- NameError: o nome 'HDAC' não está definido
Link para a Documentação de Python sobre tipos de exceções integradas
Podemos usar a exceção à nosso favor para ajudar as pessoas que estão executando o código. Podemos usar a condição try/except como um bloco if/else para procurar exceções e executar um código específico se não tivermos uma exceção e fazer algo diferente se tivermos uma exceção.
#!/usr/bin/env python3
import sys
file = ''
try:
file = sys.argv[1]
print("User provided file:" , file)
except:
print("Please provide a file name")
Precisamos "tentar" obter um argumento fornecido do usuário. Caso seja um sucesso então podemos imprimi-lá. Caso tentemos e falhemos, nós executamos o código na parte da "exceção" do nosso bloco try/except e imprimimos que precisamos do nome do arquivo.
Vamos executá-lo COM entrada do usuário
$ python3 scripts/exceptions_try.py test.txt
User provided file: test.txt
Funciona como esperado
Vamos executá-lo SEM entrada do usuário
$ python scripts/exceptions_try.py
Please provide a file name
Sim, o usuário é informado de que precisa fornecer um nome de arquivo para o script
E se o usuário fornecer uma entrada mas ela não é um arquivo válido ou o caminho está incorreto? Ou se você quer verificar se o usuário forneceu a entrada, e se é possível abrir a entrada.
Podemos adicionar múltiplos testes de exceção, como blocos if/elif. Cada declaração de "exceção" pode especificar que tipo de exceção está esperando para receber. Se esse tipo de exceção ocorrer, esse bloco do código será executado.
import sys
file = ''
try:
file = sys.argv[1]
print("User provided file name:" , file)
FASTA = open(file, "r")
for line in FASTA:
line = line.rstrip()
print(line)
except IndexError:
print("Please provide a file name")
except IOError:
print("Can't find file:" , file)
Aqui testamos um IndexError: Gerado quando um índice não é encontrado em uma sequência. O IndexError ocorre quando tentamos acessar um elemento de lista que não existe. E testamos um IOError: Gerado quando uma operação de entrada/saída falha, como a instrução print ou a função open() ao tentar abrir um arquivo que não existe. O IOError ocorre quando tentamos acessar um arquivo que não existe.
Vamos executá-lo com um arquivo que não existe.
$ python scripts/exceptions_try_files.py test.txt
User provided file name: test.txt
Can't find file: test.txt
Isso informa ao usuário que eles forneceram uma entrada, no entanto, que o arquivo listado não pode ser encontrado.
Vamos executá-lo sem nenhuma entrada
$ python scripts/exceptions_try_files.py
Please provide a file name
Isso informa ao usuário que ele precisa fornecer um arquivo.
Vamos resumir o que cobrimos e adicionar else
e finally
.
try:
# o bloco try é executado até que uma exceção seja gerada
except _ExceptionType_:
# se houver uma exceção do tipo "ExceptionType", este bloco será executado
# pode haver mais de um bloco except, assim como um elif
except:
# se houver exceções que não sejam do tipo "ExceptionType", este bloco except será executado
else:
# o bloco else é executado após a conclusão do bloco try, o que significa que nenhuma exceção foi gerada
finally:
# o bloco finally é executado se exceções forem ou não geradas (não importa o que aconteça)
Algumas exceções podem ser lançadas por múltiplos motivos, por exemplo, ErrorIO ocorrerá se o arquivo não existir, assim como se você não tiver permissões para lê-lo. Podemos obter mais informação observando o conteúdo dos nosso Objetos de Exceção. Sim, uma exceção é um objeto também! Os erros do sistema são armazenados no objeto de exceção. Para acessar o objeto use as
e forneça um nome de variável, como 'ex'.
file = ''
try:
file = sys.argv[1]
print("User provided file name:" , file)
FASTA = open(file, "r")
for line in FASTA:
line = line.rstrip()
print(line)
except IndexError:
print("Please provide a file name")
except IOError as ex:
print("Can't find file:" , file , ': ' , ex.strerror )
Aqui nós adicionamos
except IOError as ex
e agora nós obtemos a mensagem de 'strerror' de ex.
Execute.
$ python scripts/exceptions_try_files_as.py test.txt
User provided file name: test.txt
Can't find file: test.txt : No such file or directory
Agora nós sabemos que esse nome de arquivo ou o caminho não é válido
Nós podemos chamar ou gerar exceções também!! Isso é feito usando uma instrução raise
- Primeiro, criamos um novo objeto de exceção, ou seja,
ValueError()
- Use o objeto de exceção em uma frase com "Raise"
raise ValueError('your message')
Vamos gerar uma exceção se o nome do arquivo não terminar em 'fa'
import sys
file = ''
try:
file = sys.argv[1]
print("User provided file name:" , file)
if not file.endswith('.fa'):
raise ValueError("Not a FASTA file")
FASTA = open(file, "r")
for line in FASTA:
print(line)
except IndexError:
print("Please provide a file name")
except IOError as ex:
print("Can't find file:" , file , ': ' , ex.strerror )
Aqui geramos uma exceção conhecida, 'ValueError', se o arquivo não terminar com (usamos o método
endswith()
).
Vamos executá-lo.
$ python scripts/exceptions_try_files_raise.py test.txt
User provided file name: test.txt
Traceback (most recent call last):
File "scripts/exceptions_try_files_raise.py", line 10, in <module>
raise ValueError("Not a FASTA file")
ValueError: Not a FASTA file
Nossa exceção é gerada, agora vamos fazer algo com ela.
import sys
file = ''
try:
file = sys.argv[1]
print("User provided file name:" , file)
if not file.endswith('.fa'):
raise ValueError("Not a FASTA file")
FASTA = open(file, "r")
for line in FASTA:
print(line)
except IndexError:
print("Please provide a file name")
except ValueError:
print("File needs to be a FASTA file and end with .fa")
except IOError as ex:
print("Can't find file:" , file , ': ' , ex.strerror )
Aqui criamos uma exceção para capturar qualquer ValueError.
Vamos executá-lo.
$ python scripts/exceptions_try_files_raise_value.py test.txt
User provided file name: test.txt
File needs to be a FASTA file and end with .fa
Agora temos uma ótima mensagem de erro.
Mas e se houver outro ValueError, como podemos saber se tem algo a ver com a extensão do arquivo FASTA ou não? Resposta: a mensagem será diferente.
Podemos criar nossa própria exceção personalizada. Precisaremos criar uma nova classe de exceção. Abaixo está a sintaxe para fazer isso.
import sys
class NotFASTAError(Exception):
pass
file = ''
try:
file = sys.argv[1]
print("User provided file name:" , file)
if not file.endswith('.fa'):
raise NotFASTAError("Not a FASTA file")
FASTA = open(file, "r")
for line in FASTA:
print(line)
except IndexError:
print("Please provide a file name")
except NotFASTAError:
print("File needs to be a FASTA file and end with .fa")
except IOError as ex:
print("Can't find file:" , file , ': ' , ex.strerror )
Aqui criamos uma nova classe de exceção chamada 'NotFASTAError'. Em seguida, levantamos esta nova exceção.
Vamos executá-lo.
$ python scripts/exceptions_try_files_raise_try.py test.txt
User provided file name: test.txt
File needs to be a FASTA file and end with .fa
Nossa nova classe de exceção, NotFASTAError, funciona da mesma forma que as exceções integradas.
Funções consistem em várias linhas de código que fazem algo útil e que você deseja executar mais de uma vez. Existem funções integradas em Python. Você também pode escrever as suas próprias. Além disso, você dá um nome à sua função para poder se referir a ela em seu código. Isso evita copiar e colar o mesmo código em muitos lugares em seu script e torna seu código mais fácil de ler.
Vamos ver alguns exemplos.
Python tem funções integradas
>>> print('Hello world!')
Hello world!
>>> len('AGGCT')
5
Você pode definir suas próprias funções com def
. Vamos escrever uma função que calcula o conteúdo de GC. Vamos definir isso como a fração de nucleotídeos em uma sequência de DNA que são G ou C. Isso pode variar de 0 a 1.
Primeiro, podemos olhar para o código que faz o cálculo, depois podemos converter essas linhas de código em uma função.
Código para encontrar o conteúdo de GC:
dna = 'GTACCTTGATTTCGTATTCTGAGAGGCTGCTGCT'
c_count = dna.count('C') # count é um método de string
g_count = dna.count('G')
dna_len = len(dna) # len é uma função
gc_content = (c_count + g_count) / dna_len # fração de 0 a 1
print(gc_content)
Usamos def
para definir nossa própria função. É seguido pelo nome da função (gc_content
) e parâmetros que serão inseridos entre parênteses. Um dois pontos é o último caractere na linha def
. As variáveis de parâmetro estarão disponíveis para o seu código dentro da função para usar.
def gc_content(dna): # dê um nome à nossa função e ao parâmetro 'dna'
c_count = dna.count('C')
g_count = dna.count('G')
dna_len = len(dna)
gc_content = (c_count + g_count) / dna_len
return gc_content # retorna o valor para o código que chamou esta função
Aqui está uma função personalizada que você pode usar como uma função integrada do Python
Isso é igual a qualquer outra função python. Você escreve o nome da função com quaisquer variáveis que deseja passar para a função entre parênteses. No exemplo abaixo, o conteúdo de dna_string
é passado para gc_content()
. Dentro da função, esses dados são passados para a variável dna
.
dna_string = "GTACCTTGATTTCGTATTCTGAGAGGCTGCT"
print(gc_content(dna_string))
Este código imprimirá 0,45161290322580644 na tela. Você pode salvar esse valor em uma variável para usar posteriormente em seu código, assim:
dna_gc = gc_content('GTACCTTGATTTCGTATTCTGAGAGGCTGCT')
Como você pode ver, podemos escrever uma linha de código python clara e, como a função tem um nome que descreve o que ela faz, é fácil entender como o código funciona. Não dê nomes às suas funções como esta def my_function(a):
!
Como você poderia converter a fração GC em % GC. Use format()
.
dna_string = "GTACCTTGATTTCGTATTCTGAGAGGCTGCT"
dna_gc = gc_content(dna_string)
pc_gc = '{:.2%}'.format(dna_gc)
print('This sequence is' , pc_gc , 'GC')
Aqui está a saída
This sequence is 45.16% GC
- Você define uma função com
def
. Você precisa definir uma função antes de poder chamá-la. - A função deve ter um nome. Este nome deve descrever claramente o que a função faz. Aqui está o nosso exemplo
gc_content
. - Você pode passar variáveis para funções, mas não é obrigatório. Na linha de definição, você coloca as variáveis que sua função precisa entre parênteses, assim
(dna)
. Esta variável existe apenas dentro da função. - A primeira linha da função deve terminar com um
:
para que a linha completa de definição da função pareça com issodef gc_content(dna):
- As próximas linhas de código, o corpo da função, precisam estar indentadas. Este código compreende o que a função faz.
- Você pode retornar um valor como a última linha da função, mas isso não é obrigatório. Esta linha
return gc_content
no final da definição de nossa função passa o valor de conteudo_gc de volta para o código que chamou a função em seu script principal.
Você pode nomear suas variáveis de argumento como quiser, mas o nome deve descrever os dados contidos. O nome precisa ser consistente dentro de sua função.
Argumentos podem ser nomeados e esses nomes podem ser usados quando a função é chamada. Este nome é chamado de 'palavra-chave'
>>> dna_string = "GTACCTTGATTTCGTATTCTGAGAGGCTGCT"
>>> print(gc_content(dna_string))
0.45161290322580644
>>> print(gc_content(dna=dna_string)
0.45161290322580644
A palavra-chave deve ser a mesma que o argumento definido da função. Se uma função tiver múltiplos argumentos, usar a palavra-chave permite chamar a função com os argumentos em qualquer ordem.
Como definido acima, nossa função está esperando um argumento (dna
) na definição. Você recebe um erro se chamar a função sem quaisquer parâmetros.
>>> gc_content()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: gc_content() missing 1 required positional argument: 'dna'
Você pode definir valores padrão para argumentos quando definir sua função.
def gc_content(dna='N'): # dê um nome à nossa função e parâmetro 'dna'
c_count = dna.count('C')
g_count = dna.count('G')
dna_len = len(dna)
gc_content = (c_count + g_count) / dna_len
return gc_content # retorna o valor para o código que chamou esta função
Se você chamar a função sem argumentos, o padrão será usado. Neste caso, um padrão é bastante inútil, e a função retornará '0' se chamada sem fornecer uma sequência de DNA.
Expressões Lambda podem ser usadas para definir funções simples (de uma linha). Existem alguns usos para lambda que não vamos discutir aqui. Estamos mostrando a você porque às vezes você vai encontrar.
Aqui está uma função personalizada de uma linha, como as funções sobre as quais já falamos:
def get_first_codon(dna):
return dna[0:3]
print(get_first_codon('ATGTTT'))
Isso imprimirá
ATG
Aqui está a mesma função escrita como uma lambda
get_first_codon = lambda dna : dna[0:3]
print(get_first_codon('ATGTTT'))
Isso também imprime
ATG
. lambdas só podem conter uma linha e não há instrução dereturn
.
Compreensões de lista frequentemente podem ser usadas em vez de lambdas e podem ser mais fáceis de ler. Você pode ler mais sobre lambda
, particularmente em relação ao map
que irá realizar uma operação em uma lista, mas geralmente um laço for
é mais fácil de ler.
Quase todas as variáveis Python são globais. Isso significa que estão disponíveis em todo o seu código. Lembre-se de que os blocos Python são definidos como código no mesmo nível de indentação.
#!/usr/bin/env python3
print('Antes do bloco if')
x = 100
print('x=',x)
if True: # esta condição if será sempre Verdadeira
# queremos garantir que o bloco seja executado
# para que possamos mostrar o que acontece
print('Dentro do bloco if')
x = 30
y = 10
print("x=", x)
print("y=", y)
print('Após o bloco if')
print("x=", x)
print("y=", y)
Vamos executar:
$ python3 scripts/scope.py
Antes do bloco if
x= 100
Dentro do bloco if
x= 30
y= 10
Após o bloco if
x= 30
y= 10
A exceção mais importante às variáveis serem globais é que variáveis definidas em funções são locais, ou seja, existem apenas dentro de sua função. Dentro de uma função, as variáveis globais são visíveis, mas é melhor passar variáveis para uma função como argumentos.
def show_n():
print(n)
n = 5
show_n()
A saída é esta 5
, como você esperaria, mas o exemplo abaixo é uma prática de programação melhor. Por quê? Veremos um pouco mais tarde.
def show_n(n):
print(n)
n = 5
show_n(n)
Variáveis dentro de funções são locais e, portanto, só podem ser acessadas de dentro do bloco da função. Isso se aplica tanto a argumentos quanto a variáveis definidas dentro de uma função.
#!/usr/bin/end python3
def set_local_x_to_five(x):
print('Dentro de def')
x = 5 # localmente para set_local_x_to_five()
y=5 # também local
print("x =",x)
print("y = ",y)
print('Após def')
x = 100 # global x
y = 100 # global
print('x=',x)
print('y=',y)
set_local_x_to_five(500)
print('Após chamada da função')
print('x=',x)
print('y=',y)
Aqui adicionamos uma função set_local_x_to_five
com um argumento chamado 'x'. Esta variável existe apenas dentro da função, onde substitui qualquer variável com o mesmo nome fora do def
. Dentro do def
, também inicializamos uma variável y
que substitui qualquer y
global dentro do def
.
Vamos executá-lo:
$ python3 scope_w_function.py
Após def
x= 100
y= 100
Dentro de def
x = 5
y = 5
Após chamada da função
x= 100
y= 100
Há uma variável global,
x
= 100, mas quando a função é chamada, ela cria uma nova variável local, também chamadax
, com valor = 5. Esta variável desaparece depois que a função termina e voltamos a usar a variável globalx
= 100. O mesmo vale paray
.
Você pode tornar uma variável local global com a declaração global
. Agora, uma variável que você usa em uma função é a mesma variável no restante do código. É melhor não definir nenhuma variável como global até que você saiba que precisa, porque você pode modificar o conteúdo de uma variável sem querer.
Aqui está um exemplo de uso do global
.
#!/usr/bin/env python3
def set_global_variable():
global greeting # torna a variável "greeting" global
greeting = "Eu digo olá"
greeting = 'Bom dia'
print('Antes da chamada de função')
print('greeting =',greeting)
#fazendo a chamada da função
set_global_variable()
print('Após a chamada de função')
print('greeting =',greeting)
Vamos olhar a saída!
$ python3 scripts/scope_global.py
Antes da chamada de função
greeting = Bom dia
Após a chamada de função
greeting = Eu digo olá
Observe que a função alterou o valor da variável global. Pode ser algo que você não queira fazer.
Ao criar novas variáveis locais dentro das definições de função, o Python impede que variáveis com o mesmo nome se sobreponham por engano.
O Python vem com algumas funções e métodos principais. Existem muitos módulos úteis que você desejará usar. import
é a declaração para informar ao seu script que você deseja usar código em um módulo. Como já vimos com expressões regulares, você pode trazer código que manipula expressões regulares com import re
.
Como você obtém informações sobre um módulo? O Python possui páginas de ajuda incorporadas na linha de comando, como man
que encontramos anteriormente na palestra sobre Unix. As informações online podem ser mais atualizadas. Pesquise em https://docs.python.org/3.6/. Mas se você não tiver acesso à internet, sempre pode usar pydoc
. Para saber mais sobre o módulo re
, digite pydoc re
na linha de comando. A última linha na saída informa onde o módulo Python está instalado.
% pydoc re
Ajuda sobre o módulo re:
NOME
re - Suporte para operações de correspondência de expressões regulares (RE).
REFERÊNCIA DO MÓDULO
https://docs.python.org/3.6/library/re
A seguinte documentação é gerada automaticamente dos arquivos-fonte do Python.
Pode estar incompleta, incorreta ou incluir recursos considerados detalhes de implementação e que podem variar entre as implementações do Python.
Em caso de dúvida, consulte a referência do módulo no local indicado acima.
DESCRIÇÃO
Este módulo fornece operações de correspondência de expressões regulares semelhantes às encontradas em Perl. Ele oferece suporte a strings de 8 bits e Unicode; tanto o padrão quanto as strings processadas podem conter bytes nulos e caracteres fora da faixa ASCII dos EUA.
As expressões regulares podem conter caracteres especiais e ordinários.
A maioria dos caracteres comuns, como "A", "a" ou "0", são as expressões regulares mais simples; eles simplesmente correspondem a si mesmos. Você pode
concatenar caracteres comuns, então o último corresponde à string 'last'.
...
ARQUIVO
/anaconda3/lib/python3.6/glob.py
Aqui estão alguns dos módulos mais comuns e úteis, juntamente com seus métodos e objetos. É um tour rápido.
os.path
possui utilitários comuns para trabalhar com caminhos de arquivos (nomes de arquivos e diretórios). Um caminho é uma lista de diretórios (geralmente terminando com um nome de arquivo) que diz onde encontrar um arquivo ou diretório.
função | descrição |
---|---|
os.path.basename(path) | qual é o último elemento do caminho? Observe que /home/tmp/ retorna '' , em vez de tmp |
os.path.dirname(path) | qual é o diretório em que o arquivo está? |
os.path.exists(path) | o caminho existe? |
os.path.getsize(path) | retorna o tamanho do caminho (arquivo) em bytes ou erro |
os.path.isfile(path) | o caminho aponta para um arquivo? |
os.path.isdir(path) | o caminho aponta para um diretório? |
os.path.splitext(path) | divide antes e depois da extensão do arquivo (por exemplo, '.txt') |
Substituído por subprocess.
Este é o módulo atual para executar linhas de comando a partir de scripts Python
import subprocess
subprocess.run(["ls","-l"]) # o mesmo que executar ls -l na linha de comando
Mais complexo que os.system()
. Você precisa especificar onde a entrada e a saída vão. Vamos olhar sobre isso com mais mais detalhes
Digamos que queremos encontrar todos os arquivos que têm o usuário amanda (ou no nome do arquivo)
ls -l | grep amanda
torna-se este 'atalho' que capturará a saída dos dois comandos unix na variável output
import subprocess
output = subprocess.check_output('ls -l | grep amanda', shell = True)
Isso é melhor do que alternativas com subprocess.run()
. Isso é equivalente à string unix citada com backtick.
output
contém um objeto de bytes (mais ou menos uma string de codificações de caracteres ASCII)
b'-rw-r--r-- 1 amanda staff 161952 Oct 2 18:03 test.subreads.fa\n-rw-r--r-- 1 amanda staff 126 Oct 2 13:23 test.txt\n'
Você pode converter decodificando o objeto de bytes em uma string
>>>output.decode('utf-8')
'-rw-r--r-- 1 amanda staff 161952 Oct 2 18:03 test.subreads.fa\n-rw-r--r-- 1 amanda staff 126 Oct 2 13:23 test.txt\n'
Vamos supor que ls -l
gera alguma saída algo assim
total 112
-rw-r--r-- 1 amanda staff 69 Jun 14 17:41 data.cfg
-rw-r--r-- 1 amanda staff 161952 Oct 2 18:03 test.subreads.fa
-rw-r--r-- 1 amanda staff 126 Oct 2 13:23 test.txt
Como nós executamos ls -l
no Python e capturamos a saída (stdout)?
import subprocess
rtn = subprocess.run(['ls','-l'], stdout=subprocess.PIPE ) # especifique que você deseja capturar STDOUT
bytes = rtn.stdout
stdout = bytes.decode('utf-8')
# algo como
lines = stdout.splitlines()
lines
agora contêm elementos de cada linha da saída de ls -l
, incluído a linha do cabeçalho, que não é um arquivo
>>> lines[0]
'total 112'
>>> lines[1]
'-rw-r--r-- 1 amanda staff 69 Jun 14 17:41 data.cfg'
Para executar um comando e verificar o status da saída (realmente para verificar se o status da saída foi ok ou zero) use
oops = subprocess.check_call(['ls', '-l'])
# ou, simplesmente...
oops = subprocess.check_call('ls -l', shell=True)
Você não pode escrever ls -l > listing.txt
para redirecionar stdout no método subprocess, então use isso
tmp_file = 'listing.txt'
with open(tmp_file,'w') as ofh:
oops = subprocess.check_call(['ls', '-l'], stdout=ofh )
Algumas variáveis úteis para iniciantes. Muitos mais parâmetros e configurações avançadas do sistema que não estamos cobrindo aqui.
função | descrição |
---|---|
sys.argv | lista de parâmetros da linha de comando |
sys.path | onde o Python deve procurar módulos |
Consulte as notas sobre expressões regulares
Listas etc. melhores
from collections import deque
copy.copy()
e
copy.deepcopy()
Link para mais informações sobre cópia profunda vs. cópia rasa
função | descrição |
---|---|
math.exp() | e**x |
math.log2() | log base 2 |
math.log10() | log base 10 |
math.sqrt() | raiz quadrada |
math.sin() | seno |
math.pi(), math.e() | constantes |
etc |
veja também numpy
Números aleatórios gerados por computadores não são verdadeiramente aleatórios, então o Python os chama de pseudo-aleatórios.
exemplo | descrição |
---|---|
random.seed(1) | define a semente inicial para a sequência pseudo-aleatória como 1 para possibilitar a reprodutibilidade |
random.randrange(9) | inteiro entre 0 e 8 |
random.randint(1,5) | inteiro entre 1 e 5 |
random.random() | float entre 0 e 1 |
random.uniform(1,2) | float entre 1 e 2 |
random.choice(my_genes) | retorna um elemento aleatório da sequência |
Para obter um índice aleatório de um elemento de list
, use i=random.randrange(len(list))
Quantidades estatísticas típicas
exemplo | descrição |
---|---|
statistics.mean([1,2,3,4,5]) | média ou média |
statistics.median([ 2,3,4,5]) | mediana = 3,5 |
statistics.stdev([1,2,3,4,5]) | desvio padrão da amostra (raiz quadrada da variância da amostra) |
statistics.pstdev([1,2,3,4,5]) | estimativa do desvio padrão da população |
Realiza expansão de caminho de arquivo com curingas semelhantes ao Unix.
>>> import glob
>>> glob.glob('pdfs/*.pdf')
['pdfs/python1.pdf', 'pdfs/python2.pdf', 'pdfs/python3.pdf', 'pdfs/python4.pdf', 'pdfs/python6.pdf', 'pdfs/python8.pdf', 'pdfs/unix1.pdf', 'pdfs/unix2.pdf']
>>> fasta_files = glob.glob('sequences/*.fa')
>>>
Ferramenta excelente (embora bastante complicada) para analisar argumentos da linha de comando e gerar automaticamente mensagens de ajuda para scripts (muito útil!). Aqui está um script simples que explica um pouco do que ele faz.
#!/usr/bin/env python3
import argparse
parser = argparse.ArgumentParser(description="A test program that reads in some number of lines from an input file. The output can be screen or an output file")
# queremos que o primeiro argumento seja o nome do arquivo
parser.add_argument("file", help="path to input fasta filename")
# segundo argumento será o número da linha
# o tipo padrão é string, precisa especificar se espera um inteiro
parser.add_argument("lines", type=int, help ="how many lines to print")
# argumento outfile opcional especificado com -o ou --out
parser.add_argument("-o","--outfile", help = "optional: supply output filename, otherwise write to screen", dest = 'out')
args = parser.parse_args()
# os argumentos aparece em args
filename = args.file
lines = args.lines
if args.out:
print("writing output to", args.out)
Com este módulo, a ajuda -h vem de graça. Os argumentos --outfile são opcionais, a menos que você escreva 'required=True', assim
parser.add_argument('-f', "-fasta", required=True, help='Output fasta filename', dest='outfile')
Tempo, HTML, XML, e-mail, CGI, soquetes, áudio, interfaces gráficas de usuário com Tk, depuração, teste, utilitários Unix.
Além disso, são essenciais: BioPython para bioinformática, Numpy para matemática e estatísticas, pandas para dados, scikit-learn para aprendizado de máquina.
As vantagens de escrever classes e escrever funções são muito semelhantes.
Quando escrevemos funções, agrupamos funções principais do Python e métodos para criar uma coleção única de instruções que ocorrem em uma ordem específica.
Essas novas funções tornam nosso código mais fácil de ler e escrever, especialmente se você for usar a função muitas vezes.
Uma diferença conceitual entre uma função e uma classe é que uma função geralmente faz uma coisa, enquanto uma classe fará muitas coisas relacionadas para ajudar a resolver um problema.
O que é uma classe de verdade, o que ela faz? Uma classe na verdade não faz nada, exceto definir uma lista de regras para criar um novo objeto personalizado. Toda vez que você usa a classe, está criando uma instância de um tipo de objeto.
Você já tem usado classes para criar objetos. Aqui estamos usando a função open
para criar duas instâncias de um objeto de arquivo. Uma instância contém informações sobre um arquivo FASTA enquanto a outra contém informações sobre um arquivo GFF.
fa_input = open("somedata.fa")
gff_input = open("somedata.gff")
Classes criam objetos, e esses objetos terão atributos e métodos associados a eles.
Métodos
Métodos são funções que pertencem a objetos de uma classe específica.
Atributos
Atributos são variáveis que estão associadas a um objeto de uma classe específica.
Definir uma classe é objetivo.
O primeiro passo é decidir quais atributos e quais métodos ela terá.
Criar uma Classe DNARecord
Quando criamos uma classe, na verdade estamos estabelecendo uma série de regras que um objeto DNARecord deve seguir.
Regras do DNARecord:
- O DNARecord deve ter uma sequência [atributo]
- O DNARecord deve ter um nome [atributo]
- O DNARecord deve ter um organismo [atributo]
- O DNARecord será capaz de calcular o conteúdo de AT [método]
- O DNARecord será capaz de calcular o complemento reverso [método]
Aqui está o primeiro rascunho, mas não final, da nossa classe. Vamos passar por cada seção deste código abaixo:
class DNARecord(object):
# definir atributos da classe
sequence = 'ACGTAGCTGACGATC'
gene_name = 'ABC1'
species_name = 'Drosophila melanogaster'
# definir métodos
def reverse_complement(self):
replacement1 = self.sequence.replace('A', 't')
replacement2 = replacement1.replace('T', 'a')
replacement3 = replacement2.replace('C', 'g')
replacement4 = replacement3.replace('G', 'c')
reverse_comp = replacement4[::-1]
return reverse_comp.upper()
def get_AT(self):
length = len(self.sequence)
a_count = self.sequence.count('A')
t_count = self.sequence.count('T')
at_content = (a_count + t_count) / length
return at_content
## criar um novo objeto DNARecord
dna_rec_obj = DNARecord()
## Use o novo objeto DNARecord
print('Um novo registro para ' + dna_rec_obj.gene_name + ' foi criado de ' + dna_rec_obj.species_name)
print('AT é ' + str(dna_rec_obj.get_AT()))
print('A fita complementar é ' + dna_rec_obj.reverse_complement())
Agora vamos passar por cada seção:
Começamos com a palavra-chave class
, seguida pelo nome da nossa classe DNARecord
com o nome da classe base entre parênteses object
.
class DNARecord(object):
Em seguida, definimos os atributos da classe. Estas são variáveis com dados que pertencem à classe e, portanto, a qualquer objeto que seja criado usando esta classe.
# definir atributos da classe
sequence = 'ACGTAGCTGACGATC'
gene_name = 'ABC1'
species_name = 'Drosophila melanogaster'
A seguir, definimos nossos métodos de classe:
# define métodos
def reverse_complement(self):
replacement1 = self.sequence.replace('A', 't')
replacement2 = replacement1.replace('T', 'a')
replacement3 = replacement2.replace('C', 'g')
replacement4 = replacement3.replace('G', 'c')
reverse_comp = replacement4[::-1]
return reverse_comp.upper()
def get_AT(self):
length = len(self.sequence)
a_count = self.sequence.count('A')
t_count = self.sequence.count('T')
at_content = (a_count + t_count) / length
return at_content
Os métodos estão usando um argumento chamado self
, ou seja, length = len(self.sequence)
. Esta é uma variável especial que você usa dentro de uma classe. Com ela, você pode acessar todos os dados que estão contidos dentro do objeto quando ele é criado.
Use o formato self.attribute
para recuperar o valor das variáveis criadas dentro da classe. Aqui usamos self.sequence
para recuperar as informações armazenadas em nosso atributo chamado sequence
.
replacement1 = self.sequence.replace('A', 't')
A classe acima é um conjunto de regras que precisam ser seguidas ao criar um novo objeto DNARecord. Agora vamos criar um novo objeto DNARecord:
dna_rec_obj = DNARecord()
dna_rec_obj
é o nosso novo objeto DNARecord que foi criado usando as regras que estabelecemos na definição da classe.
Agora que um novo objeto DNARecord foi criado e atribuído à variável dna_rec_obj
, podemos acessar seus atributos usando o seguinte formato, objeto.nome_do_atributo
.
Para obter o nome do gene do objeto que criamos, simplesmente escrevemos dna_rec_obj.gene_name
.
Isso é possível porque dentro da nossa definição de classe criamos uma variável gene_name
.
Vamos tentar:
>>> dna_rec_obj.gene_name
'ABC1'
>>> dna_rec_obj.sequence
'ACGTAGCTGACGATC'
Para chamar um método associado ao nosso novo objeto, usamos um formato similar, objeto.nome_do_método
.
Então, para chamar
o método get_AT()
, usaríamos dna_rec_obj.get_AT()
. Isso deve parecer familiar, você já usou métodos de classe várias vezes: alguma_string.count('A')
.
Vamos tentar com nosso dna_rec_obj
:
>>> dna_rec_obj.sequence
'ACGTAGCTGACGATC'
>>> dna_rec_obj.get_AT()
0.4666666666666667
Agora vamos usar o método reverse_complement()
>>> dna_rec_obj.sequence
'ACGTAGCTGACGATC'
>>> dna_rec_obj.reverse_complement()
GATCGTCAGCTACGT
Uau!! Obter o complemento reverso em uma linha é bem legal!
Ótimo!!!
Agora podemos criar um objeto DNARecord e recuperar os atributos do objeto e usar os métodos legais que criamos.
Mas..... Ele sempre contém o mesmo nome de gene, sequência e informações de espécie 😟
Vamos tornar nossa classe mais genérica, ou em outras palavras, fazer com que um usuário possa fornecer um novo nome de gene, sequência de gene e organismo de origem toda vez que um objeto DNARecord for criado.
Para fazer isso, precisamos adicionar uma função __init__
à nossa Regra de Objeto, ou Classe.
A função init
será chamada automaticamente quando você criar um objeto.
Ela contém instruções específicas para criar um novo Objeto DNARecord.
Ela especifica quantos dados queremos coletar do criador de um objeto DNARecord para usar dentro de um objeto DNARecord.
Abaixo, nossas instruções __init__ indicam que queremos criar atributos de objeto chamados sequence
, gene_name
e species_name
e defini-los com os valores fornecidos como argumentos quando o objeto foi criado.
Aqui está a definição da nossa nova classe e a criação de um novo objeto ao usar a função __init__:
#!/usr/bin/env python3
class DNARecord(object):
# definir atributos da classe
def __init__(self, sequence, gene_name, species_name): ## observe que '__init__' está envolto com dois sublinhados
#sequence = 'ACGTAGCTGACGATC'
#gene_name = 'ABC1'
#species_name = 'Drosophila melanogaster'
self.sequence = sequence
self.gene_name = gene_name
self.species_name = species_name
# define methods
def reverse_complement(self):
replacement1 = self.sequence.replace('A', 't')
replacement2 = replacement1.replace('T', 'a')
replacement3 = replacement2.replace('C', 'g')
replacement4 = replacement3.replace('G', 'c')
reverse_comp = replacement4[::-1]
return reverse_comp.upper()
def get_AT(self):
length = len(self.sequence)
a_count = self.sequence.count('A')
t_count = self.sequence.count('T')
at_content = (a_count + t_count) / length
return at_content
## Criar novos Objetos DNARecord com dados definidos pelo usuário
dna_rec_obj_1 = DNARecord('ACTGATCGTTACGTACGAGT', 'ABC1', 'Drosophila melanogaster')
dna_rec_obj_2 = DNARecord('ATATATTATTATATTATA', 'COX1', 'Homo sapiens')
for d in [ dna_rec_obj_1, dna_rec_obj_2 ]:
print('name:' , d.gene_name , ' ' , 'seq:' , d.sequence)
Saída:
$ python3 dnaRecord_init.py
name: ABC1 seq: ACTGATCGTTACGTACGAGT
name: COX1 seq: ATATATTATTATATTATA
Agora você pode criar tantos Objetos DNASequence quanto desejar, cada um pode conter informações sobre uma sequência diferente.