Funções e módulos¶
Introdução¶
No programa seguinte, dada uma sequência de DNA pretende-se mostrar a sequência, a sequência complementar e o complemento reverso na forma de codões separados por um hífen.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | seq = "AGCTGGATCCTGAACGCATAGACTAGCATGGGACTAAAGGTCCATTACTGA" trans = {'A':'T', 'T':'A', 'C':'G', 'G':'C'} comp = ''.join([trans[b] for b in seq]) comp_rev = ''.join(reversed(comp)) seq_cods = [seq[i:i+3] for i in range(0, len(seq), 3)] chain_seq = '-'.join(seq_cods) print("5'-" + chain_seq +"-3'") comp_cods = [comp[i:i+3] for i in range(0, len(comp), 3)] chain_comp = '-'.join(comp_cods) print("3'-" + chain_comp + "-5'") comp_rev_cods = [comp_rev[i:i+3] for i in range(0, len(comp_rev), 3)] chain_comp_rev = '-'.join(comp_rev_cods) print('Complemento reverso') print("5'-" + chain_comp_rev + "-3'") |
5'-AGC-TGG-ATC-CTG-AAC-GCA-TAG-ACT-AGC-ATG-GGA-CTA-AAG-GTC-CAT-TAC-TGA-3' 3'-TCG-ACC-TAG-GAC-TTG-CGT-ATC-TGA-TCG-TAC-CCT-GAT-TTC-CAG-GTA-ATG-ACT-5' Complemento reverso 5'-TCA-GTA-ATG-GAC-CTT-TAG-TCC-CAT-GCT-AGT-CTA-TGC-GTT-CAG-GAT-CCA-GCT-3'
A parte do programa nas linhas 7 e 8
seq_cods = [seq[i:i+3] for i in range(0, len(seq), 3)] chain_seq = '-'.join(seq_cods)
repete-se de uma forma análoga para a sequência complementar e para o
complemento reverso nas linhas 11 e 12 e também nas linhas 15 e 16. O que
muda é a sequência sobre a qual estão a ser aplicadas (seq
nas linhas 7 e 8,
comp
nas linhas 11 e 12 e comp_rev
nas linhas 15 e 16).
O objetivo de cada grupo destas duas linhas é muito claro: separar uma sequência (string) numa listas de codões e depois construír uma string com os codões separados por um hífen.
Como podemos não repetir o "texto" destas três partes do programa, que são muito semelhantes?
Funções¶
As funções (também conhecidas como subprogramas, subrotinas, isto é, mini-programas dentro de programas) são a solução para estes casos.
Já vimos várias funções, sempre disponíveis ou disponíveis após importação de módulos:
a = 'Uma pequena string' n = len(a) f = int(4.2) nA = a.count('A') a = [] a.append(33) import math l = math.log(2.0)
Definição de funções (def
)¶
Podemos escrever outras funções para "aumentar" a linguagem.
Tal como na matemática, as funções transformam objetos noutros objetos:
Mas, tal como na matemática, as funções são escritas para atuar sobre
objetos genéricos (x
):
Problema: escrever uma função que, dada uma sequência, devolva a
sequência com os codões separados por -
.
def seqcods(x): cods = [x[i:i+3] for i in range(0,len(x),3)] comhifen = '-'.join(cods) return comhifen
Anatomia de uma função¶
A definição de uma função (def
) não executa nada imediatamente.
É necessário chamar (ou "invocar") a função para esta ser usada:
def seqcods(x): cods = [x[i:i+3] for i in range(0,len(x),3)] comhifen = '-'.join(cods) return comhifen a = "ATGGTTACCTAGTATTTAGGATTA" print(a) # A função é chamada aqui: s = seqcods(a) print(s)
ATGGTTACCTAGTATTTAGGATTA ATG-GTT-ACC-TAG-TAT-TTA-GGA-TTA
Nota
O comando return
pode "devolver" uma expressão complicada
(não só o nome de um objeto)
def seqcods(x): return '-'.join( [x[i:i+3] for i in range(0,len(x),3)]) a = "ATGGTTACCTAGTATTTAGGATTA" print(a) # A função é chamada aqui: s = seqcods(a) print(s)
ATGGTTACCTAGTATTTAGGATTA ATG-GTT-ACC-TAG-TAT-TTA-GGA-TTA
Em resumo:
A linha
def seqcods(x):
"regista" uma nova função, chamada seqcods
, que pode ser usada em
qualquer ponto do programa, da forma seguinte:
s = seqcods(a)
Entrada e saída de valores quando uma função é chamada:
Exemplo: função factorial()
:
def factorial(n): res = 1 for k in range(2,n+1): res = res * k return res print(factorial(200))
788657867364790503552363213932185062295135977687173263294742533244359449963403342920304284011984623904177212138919638830257642790242637105061926624952829931113462857270763317237396988943922445621451664240254033291864131227428294853277524242407573903240321257405579568660226031904170324062351700858796178922222789623703897374720000000000000000000000000000000000000000000000000
Vários tipos de funções¶
a = 'Uma pequena string' #1 argumento, 1 resultado print( len(a) ) #1 arg, 1 res, associada a um objeto (string a) print( a.count('a') ) #0 arg, 1 res, associada a um objeto (string a) print( a.upper() )
18 2 UMA PEQUENA STRING
#1 arg, 0 res, associada a um objeto (lista b) # modifica o objeto (a lista b) b = [12, 24] print( b.append(36) ) print(b)
None [12, 24, 36]
Além da função .append()
, recordar que as listas têm outras duas
funções deste tipo, que modificam a lista sem produzir nenhum resultado
(o resultado é a constante None
): .reverse()
e .sort()
.
b = [12, 24, 36] print(b) b.reverse() print(b) b.sort() print(b)
[12, 24, 36] [36, 24, 12] [12, 24, 36]
As funções podem ter mais de um argumento.
O resultado pode não ser apenas um número ou uma string: as funções podem devolver uma lista inteira, um dicionário ou outros objetos mais complexos.
import math print( math.log(64, 2) ) import time x = time.localtime(time.time()) print(x)
6.0 time.struct_time(tm_year=2018, tm_mon=4, tm_mday=8, tm_hour=18, tm_min=39, tm_sec=43, tm_wday=6, tm_yday=98, tm_isdst=1)
Problema: eliminar valores de uma lista que pertençam a uma "lista negra"
def elimin_black(uma_lista, black_list): res = [i for i in uma_lista if i not in black_list] return res a = [1, 2, 4, 'um', 'dois', 3, 42, 'quatro'] print(a) black = [1, 2, 'um', 'dois'] print ('\nA eliminar:', black) clean = elimin_black(a, black) print(clean)
[1, 2, 4, 'um', 'dois', 3, 42, 'quatro'] A eliminar: [1, 2, 'um', 'dois'] [4, 3, 42, 'quatro']
Problema: dado um nome de um ficheiro de texto, escrever uma
função para ler o conteúdo do ficheiro para uma lista de linhas sem o
\n
no final, excluíndo as linhas vazias.
def ler_fich(nome): linhas = [] with open(nome) as a: for linha in a: linha = linha.strip() if len(linha) > 0: linhas.append(linha) return linhas todos = ler_fich('gre3.txt') for i in todos: print(i)
>sp|P38715|GRE3_YEAST NADPH-dependent aldose reductase GRE3 OS=Saccharomyces cerevisiae (strain ATCC 204508 / S288c) GN=GRE3 PE=1 SV=1 MSSLVTLNNGLKMPLVGLGCWKIDKKVCANQIYEAIKLGYRLFDGACDYGNEKEVGEGIR KAISEGLVSRKDIFVVSKLWNNFHHPDHVKLALKKTLSDMGLDYLDLYYIHFPIAFKYVP FEEKYPPGFYTGADDEKKGHITEAHVPIIDTYRALEECVDEGLIKSIGVSNFQGSLIQDL LRGCRIKPVALQIEHHPYLTQEHLVEFCKLHDIQVVAYSSFGPQSFIEMDLQLAKTTPTL FENDVIKKVSQNHPGSTTSQVLLRWATQRGIAVIPKSSKKERLLGNLEIEKKFTLTEQEL KDISALNANIRFNDPWTWLDGKFPTFA
Problema: eliminar valores repetidos numa lista
def elimin_reps(uma_lista): res = [] for i in uma_lista: if i not in res: res.append(i) return res uma_lista = [1, 2, 4, 7, 7, 5, 8, 8, 9, 10] print(uma_lista) clean = elimin_reps(uma_lista) print(clean)
[1, 2, 4, 7, 7, 5, 8, 8, 9, 10] [1, 2, 4, 7, 5, 8, 9, 10]
Note-se que na função é criada uma lista nova:
res = [] ... res.append(i)
e é esta lista que é o resultado da função.
Problema: eliminar valores repetidos numa lista, mas sem ser
devolvida uma lista nova como resultado. Isto é, a função recebe uma
lista e modifica-a, não havendo return
.
def elimin_reps2(uma_lista): res = [] for i in uma_lista: if i not in res: res.append(i) uma_lista[:] = res uma_lista = [1, 2, 4, 7, 7, 5, 8, 8, 9, 10] print('Antes', uma_lista) elimin_reps2(uma_lista) # não havendo return NÃO se dá um nome # ao resultado print('Depois', uma_lista)
Antes [1, 2, 4, 7, 7, 5, 8, 8, 9, 10] Depois [1, 2, 4, 7, 5, 8, 9, 10]
O que significa uma_lista[:] = res
?
Usa-se um slice para toda a lista (uma_lista[:]
significa todos os
elementos do princípio o fim)e atribuí-se a esse slice uma lista nova.
Assim, toda a lista é modificada.
Nota: não é possível usar esta técnica com strings. As strings são imutáveis.
Se as funções tiverem resultados é possível usá-las em cadeia:
def elimin_reps(uma_lista): res = [] for i in uma_lista: if i not in res: res.append(i) return res def elimin_black(uma_lista, black_list): return [i for i in uma_lista if i not in black_list] a = [1, 2, 4, 'um', 'dois', 3, 3, 37, 42, 42, 'quatro'] black = [1, 2, 'um', 'dois'] clean = elimin_reps(elimin_black(a, black)) print(clean)
[4, 3, 37, 42, 'quatro']
Âmbito dos nomes¶
def recta(m, b, x): print('Para x =', x) print('com m =', m) print('com b =', b) r1 = m*x r0 = b return(r1 + r0) x, c1, c0 = 2.0, 3.0, 2.0 res = recta(c1, c0, x) print('Resultado:', res)
Para x = 2.0 com m = 3.0 com b = 2.0 Resultado: 8.0
Este programa corre sem problemas.
Note-se que podemos usar a função print()
dentro de uma função.
def recta(m, b, x): r1, r0 = m*x, b return r1 + r0 m, b, x = 2.0, 3.0, 2.0 res = recta(m, b, x) print('Para x =', x, 'm =', m, 'b =', b) print('m*x =', r1, 'b =', r0) print('Resultado:', res)
Para x = 2.0 m = 2.0 b = 3.0
:
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-17-f26c93717bbe> in <module>() 7 8 print('Para x =', x, 'm =', m, 'b =', b) ----> 9 print('m*x =', r1, 'b =', r0) 10 print('Resultado:', res) NameError: name 'r1' is not defined
O que se passou aqui?
Os nomes usados dentro da função r1
e r0
são locais: pertencem ao
âmbito da função.
Qualquer parte do programa "exterior" à função não consegue "ver" esses nomes. Daí o erro durante a execução.
O mesmo acontece aos próprios nomes locais dos argumentos da função:
def recta2(m2, b2, x): r1, r0 = m2*x, b2 return r1 + r0 m, b, x = 2.0, 3.0, 2.0 res = recta2(m, b, x) print('Para x =', x, 'm2 =', m2, 'b2 =', b2) print('Resultado:', res)
:
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-18-92c7134da27b> in <module>() 6 res = recta2(m, b, x) 7 ----> 8 print('Para x =', x, 'm2 =', m2, 'b2 =', b2) 9 print('Resultado:', res) NameError: name 'm2' is not defined
def recta(m, b, x): print('Dentro da função --------') print('m =', m, 'b =', b, 'x =', x) print('-------------------------') x = m * x + b return x m = 2 b = 2 x = 4 res = recta(m + 3, b + 3, x * x) print('m =', m, 'b =', b, 'x =', x) print('\nResultado:', res)
Dentro da função -------- m = 5 b = 5 x = 16 ------------------------- m = 2 b = 2 x = 4 Resultado: 85
Este programa corre sem problemas!
Mas cada um dos nomes m
, b
, x
é usado em dois contextos e tem
valores diferentes:
- O contexto local, quando estão "dentro" da função.
- O contexto global, quando estão "fora da função".
Fora da função, os valores globais são:
m = 2 b = 2 x = 4
Estes valores não são modificados fora da função e são apresentados pela
função print()
no final.
Dentro da função estes nomes são, em primeiro lugar, usados como os argumentos da função.
Pela maneira como a função é chamada, estes valores são:
m = 5 b = 5 x = 16
O nome x
é modificado dentro da função (x = m * x + b
) ficando com o
valor final 85 e é este valor que é o resultado da função (return x
).
Quando a função termina e estamos de novo "de fora" da função, o valor
de x
volta a ser 4, uma vez que voltamos a um contexto "global".
Argumentos de tipo _palavra-chave¶
def mix(a=1, b=0): c = a + b print('a =', a, 'b =', b, '--> return =', c) return c x = mix() x = mix(b=3) x = mix(a=2, b=3) x = mix(2,3)
a = 1 b = 0 --> return = 1 a = 1 b = 3 --> return = 4 a = 2 b = 3 --> return = 5 a = 2 b = 3 --> return = 5
def factorial(n, trace=False): p = 1 for i in range(2,n+1): p = p * i if trace: print(i, p) return p f20 = factorial(20) print('O factorial de 20 é', f20)
O factorial de 20 é 2432902008176640000
def factorial(n, trace=False): p = 1 for i in range(2,n+1): p = p * i if trace: print(i, p) return p f20 = factorial(20, trace=True) print('O factorial de 20 é', f20)
2 2 3 6 4 24 5 120 6 720 7 5040 8 40320 9 362880 10 3628800 11 39916800 12 479001600 13 6227020800 14 87178291200 15 1307674368000 16 20922789888000 17 355687428096000 18 6402373705728000 19 121645100408832000 20 2432902008176640000 O factorial de 20 é 2432902008176640000
Módulos e import
¶
Como vimos, muitas funções estão imediatamente disponíveis quando começamos a escrever um programa.
Estas funções podem ser "livres" (por exemplo a função len()
) ou
associadas a objetos (por exemplo, s.split()
que está associada à
string s
).
A linguagem Python permite a organização dos programas em módulos.
Módulos são ficheiros .py (ou ficheiros pré-compilados) que contêm coleções de funções úteis e relacionadas entre si, podendo também conter alguns outros objetos que não são funções, mas que contêm informação de suporte.
Os módulos são também essenciais no aumento da funcionalidade da própria linguagem python: com a distribuição oficial do Python e em algumas distribuições de "Python científico" são tipicamente disponibilizados centenas de módulos, em que cada módulo reúne a funcionalidade adicional relacionada com um propósito particular.
Por exemplo, o módulo math
reúne funções associadas a cálculos
matemáticos (e as constantes \pi e e).
O módulo time
reúne funções e constantes relacionadas com a utilização
da data e hora.
A documentação sobre a coleção de módulos que são são disponibilizados em qualquer distribuição da linguagem Python (a chamada Biblioteca padrão (em inglês Standard Library) pode ser encontrada na documentação oficial
Por outro lado, quem escreve módulos novos pode submetê-los ao Python Package Index, conhecido como PyPi. Trata-se de um imenso depósito de módulos com contribuições de milhares de autores e em permanente crescimento.
Exemplo da construção de um módulo¶
def readFASTA(filename): """This function reads a FASTA format file and returns a pair of strings with the header and the sequence """ with open(filename) as a: lines = [line.strip() for line in a] lines = [line for line in lines if len(line) > 0] if lines[0].startswith('>'): return lines[0], ''.join(lines[1:]) else: return '', ''.join(lines) h, s = readFASTA("gre3.txt") print(f'Header:\n{h}\n\nSequence:\n{s}')
Header: >sp|P38715|GRE3_YEAST NADPH-dependent aldose reductase GRE3 OS=Saccharomyces cerevisiae (strain ATCC 204508 / S288c) GN=GRE3 PE=1 SV=1 Sequence: MSSLVTLNNGLKMPLVGLGCWKIDKKVCANQIYEAIKLGYRLFDGACDYGNEKEVGEGIRKAISEGLVSRKDIFVVSKLWNNFHHPDHVKLALKKTLSDMGLDYLDLYYIHFPIAFKYVPFEEKYPPGFYTGADDEKKGHITEAHVPIIDTYRALEECVDEGLIKSIGVSNFQGSLIQDLLRGCRIKPVALQIEHHPYLTQEHLVEFCKLHDIQVVAYSSFGPQSFIEMDLQLAKTTPTLFENDVIKKVSQNHPGSTTSQVLLRWATQRGIAVIPKSSKKERLLGNLEIEKKFTLTEQELKDISALNANIRFNDPWTWLDGKFPTFA
Vamos supor que esta seria a primeira de uma coleção de funções relacionadas com o processamento de ficheiros de texto contendo sequências usados em bioinformática (uma sequência em FASTA é apenas um exemplo).
Podemos criar um ficheiro biosequences.py contendo essa função:
Este ficheiro constitui um módulo que pode ser usado num programa.
Para isso, é necessário usar o comando import
:
import biosequences h, s = biosequences.readFASTA("gre3.txt") print(f'Header:\n{h}\n\nSequence:\n{s}')
Header: >sp|P38715|GRE3_YEAST NADPH-dependent aldose reductase GRE3 OS=Saccharomyces cerevisiae (strain ATCC 204508 / S288c) GN=GRE3 PE=1 SV=1 Sequence: MSSLVTLNNGLKMPLVGLGCWKIDKKVCANQIYEAIKLGYRLFDGACDYGNEKEVGEGIRKAISEGLVSRKDIFVVSKLWNNFHHPDHVKLALKKTLSDMGLDYLDLYYIHFPIAFKYVPFEEKYPPGFYTGADDEKKGHITEAHVPIIDTYRALEECVDEGLIKSIGVSNFQGSLIQDLLRGCRIKPVALQIEHHPYLTQEHLVEFCKLHDIQVVAYSSFGPQSFIEMDLQLAKTTPTLFENDVIKKVSQNHPGSTTSQVLLRWATQRGIAVIPKSSKKERLLGNLEIEKKFTLTEQELKDISALNANIRFNDPWTWLDGKFPTFA
Há mais duas maneiras de utilizar o comando import
:
from biosequences import readFASTA h, s = readFASTA("gre3.txt") print(f'Header:\n{h}\n\nSequence:\n{s}')
Header: >sp|P38715|GRE3_YEAST NADPH-dependent aldose reductase GRE3 OS=Saccharomyces cerevisiae (strain ATCC 204508 / S288c) GN=GRE3 PE=1 SV=1 Sequence: MSSLVTLNNGLKMPLVGLGCWKIDKKVCANQIYEAIKLGYRLFDGACDYGNEKEVGEGIRKAISEGLVSRKDIFVVSKLWNNFHHPDHVKLALKKTLSDMGLDYLDLYYIHFPIAFKYVPFEEKYPPGFYTGADDEKKGHITEAHVPIIDTYRALEECVDEGLIKSIGVSNFQGSLIQDLLRGCRIKPVALQIEHHPYLTQEHLVEFCKLHDIQVVAYSSFGPQSFIEMDLQLAKTTPTLFENDVIKKVSQNHPGSTTSQVLLRWATQRGIAVIPKSSKKERLLGNLEIEKKFTLTEQELKDISALNANIRFNDPWTWLDGKFPTFA
from biosequences import * h, s = readFASTA("gre3.txt") print(f'Header:\n{h}\n\nSequence:\n{s}')
Header: >sp|P38715|GRE3_YEAST NADPH-dependent aldose reductase GRE3 OS=Saccharomyces cerevisiae (strain ATCC 204508 / S288c) GN=GRE3 PE=1 SV=1 Sequence: MSSLVTLNNGLKMPLVGLGCWKIDKKVCANQIYEAIKLGYRLFDGACDYGNEKEVGEGIRKAISEGLVSRKDIFVVSKLWNNFHHPDHVKLALKKTLSDMGLDYLDLYYIHFPIAFKYVPFEEKYPPGFYTGADDEKKGHITEAHVPIIDTYRALEECVDEGLIKSIGVSNFQGSLIQDLLRGCRIKPVALQIEHHPYLTQEHLVEFCKLHDIQVVAYSSFGPQSFIEMDLQLAKTTPTLFENDVIKKVSQNHPGSTTSQVLLRWATQRGIAVIPKSSKKERLLGNLEIEKKFTLTEQELKDISALNANIRFNDPWTWLDGKFPTFA
Esta última maneira é desaconselhada: um módulo pode conter centenas de funções e, por isso, podem ser importados centenas de novos nomes para um programa, que podem entrar em conflito com outros nomes iguais utilizados no programa.
Um módulo pode conter outros objetos para além de funções.
A pensar em algumas operações que poderiam ser realizadas com sequências biológicas, o ficheiro biosequences.py poderia ser ampliado com as seguintes atribuições:
..... basesDNA = 'ATGC' basesRNA = 'AUGC' aa_residues = "ACDEFGHIKLMNPQRSTVWY" complement = { 'A':'T', 'T':'A', 'G':'C', 'C':'G'} complementRNA = { 'A':'U', 'U':'A', 'G':'C', 'C':'G'} gencode = { 'TTT': 'F', 'TTC': 'F', 'TTA': 'L', 'TTG': 'L', 'TCT': 'S', 'TCC': 'S', 'TCA': 'S', 'TCG': 'S', 'TAT': 'Y', 'TAC': 'Y', 'TGT': 'C', 'TGC': 'C', 'TGG': 'W', 'CTT': 'L', 'CTC': 'L', 'CTA': 'L', 'CTG': 'L', 'CCT': 'P', 'CCC': 'P', 'CCA': 'P', 'CCG': 'P', 'CAT': 'H', 'CAC': 'H', 'CAA': 'Q', 'CAG': 'Q', 'CGT': 'R', 'CGC': 'R', 'CGA': 'R', 'CGG': 'R', 'ATT': 'I', 'ATC': 'I', 'ATA': 'I', 'ATG': 'M', 'ACT': 'T', 'ACC': 'T', 'ACA': 'T', 'ACG': 'T', 'AAT': 'N', 'AAC': 'N', 'AAA': 'K', 'AAG': 'K', 'AGT': 'S', 'AGC': 'S', 'AGA': 'R', 'AGG': 'R', 'GTT': 'V', 'GTC': 'V', 'GTA': 'V', 'GTG': 'V', 'GCT': 'A', 'GCC': 'A', 'GCA': 'A', 'GCG': 'A', 'GAT': 'D', 'GAC': 'D', 'GAA': 'E', 'GAG': 'E', 'GGT': 'G', 'GGC': 'G', 'GGA': 'G', 'GGG': 'G', 'TAA': 'STOP', 'TAG': 'STOP', 'TGA': 'STOP'}
Problema: qual a sequência da proteína codificada por
AGCTGGATCCTGAACGATGCATAAGCATAGCCATAGACTAGCATGGGACTAAAGGTCCATTACTGA
Sabemos que o módulo biosequences
tem um dicionário chamado gencode
.
from biosequences import gencode def translation(seq): cods = [seq[i:i+3] for i in range(0, len(seq), 3)] prot = [] for c in cods: aa = gencode[c] if aa == 'STOP': break prot.append(aa) return ''.join(prot) seq = 'AGCTGGATCCTGAACGATGCATAAGCATAGCCATAGACTAGCATGGGACTAAAGGTCCATTACTGA' print(seq) print(translation(seq))
AGCTGGATCCTGAACGATGCATAAGCATAGCCATAGACTAGCATGGGACTAAAGGTCCATTACTGA SWILNDA
Claro que a função translation()
seria uma boa adição ao nosso módulo
biosequences
...
O projeto BioPython foi precisamente criado como uma coleção de funções e objetos que suportam a representação e transformação de sequências biológicas.
Hoje é muito mais do que isso, mas a parte central deste pacote de módulos continua a ser a funcionalidade relacionada com sequências biológicas.
Se usarmos a primeira forma do comando import
, é possível mudar o nome
do módulo (para uma forma mais abreviada), um alias, da seginte forma:
import biosequences as bs h, s = bs.readFASTA("gre3.txt") print(f'Header:\n{h}\n\nSequence:\n{s}')
Header: >sp|P38715|GRE3_YEAST NADPH-dependent aldose reductase GRE3 OS=Saccharomyces cerevisiae (strain ATCC 204508 / S288c) GN=GRE3 PE=1 SV=1 Sequence: MSSLVTLNNGLKMPLVGLGCWKIDKKVCANQIYEAIKLGYRLFDGACDYGNEKEVGEGIRKAISEGLVSRKDIFVVSKLWNNFHHPDHVKLALKKTLSDMGLDYLDLYYIHFPIAFKYVPFEEKYPPGFYTGADDEKKGHITEAHVPIIDTYRALEECVDEGLIKSIGVSNFQGSLIQDLLRGCRIKPVALQIEHHPYLTQEHLVEFCKLHDIQVVAYSSFGPQSFIEMDLQLAKTTPTLFENDVIKKVSQNHPGSTTSQVLLRWATQRGIAVIPKSSKKERLLGNLEIEKKFTLTEQELKDISALNANIRFNDPWTWLDGKFPTFA