lunes, 9 de enero de 2012

Exemplo de funcións recursivas

Donato publicaba sobre recursividade o mes pasado. Todos os exemplos de funcións de recursividade son sobre sucesións como a de Fibonacci, factorial, etc. e nunca se ven casos máis mundanos de recursividade.
Resulta que me tocou meter unha función de recursividade no noso servidor de modelado de GPCRs, e penso que como exemplo pode ser bastante útil.

O problema

No formulario de entrada aceptamos secuencias crudas en FASTA, ou ben identificadores Uniprot. Así que a función inicial era básicamente

def retrieve_url(url):
    import urllib2

    #url is something like
    #http://www.uniprot.org/uniprot/IDXXX.fasta

    try:
        my_response = urllib2.urlopen(url)
        return "".join(my_response.readlines())
    except urllib2.HTTPError:
        return False
Bastante simple: unha función anterior pásalle a esta o url depurado, despóis de comprobar si efectivamente é un ID válido de Uniprot. Esta función chama a Uniprot (que sigue o estándar REST), e obtén a secuencia en FASTA.
Bastantes secuencias empezaron a fallar, porque o servidor de Uniprot contestaba con un "300", a secuencia xa non se atopaba ahí, senón que a moveran a outra ID. Por outra parte, algo bastante habitual nesas bases de datos.

A solución

Fácilmente se deduce que hai que obter a nova ubicación do recurso movido, e ir outra vez a por él. Como xa temos a función que recupera FASTAS de Uniprot, ímola chamar desde sí mesma, e se o recurso volve dar un erro 300, vólvese a chamar ata que chega a un erro diferente ou ó FASTA apropiado

def retrieve_url(url):
    import urllib2

    try:
        my_response = urllib2.urlopen(url)
        return "".join(my_response.readlines())
    except urllib2.HTTPError, error:
        if error.code == 300: #Moved with multiple choices
            new_resource = error.info().getheader("Location")
            my_response = urllib2.urlopen(server + new_resource).readline()
            new_url = "http://www.uniprot.org/uniprot/uniprot/" + \
                      my_response.split("|")[1] + ".fasta"

            return retrieve_url(new_url)

    else:
        return False

No hay comentarios: