2015-05-25 16 views
9

Ho ottenuto un elenco di funzioni che potrebbero non riuscire, e se uno fallisce, non voglio che lo script si fermi, ma per continuare con la funzione successiva.Come evitare "un'eccezione troppo ampia" in questo caso?

sto eseguendo con qualcosa di simile:

list_of_functions = [f_a,f_b,f_c] 
for current_function in list_of_functions: 
    try: 
     current_function() 
    except Exception: 
     print(traceback.format_exc()) 

Sta lavorando bene, ma non è PEP8 compatibile:

Quando la cattura di eccezioni, menzione eccezioni specifiche ogni volta possibile, invece di utilizzare a nudo eccetto: clausola.

Ad esempio, utilizzare:

try: 
    import platform_specific_module 
except ImportError: 
    platform_specific_module = None 

A nuda ad eccezione di: clausola di cattura SystemExit e KeyboardInterrupt eccezioni, rendendo più difficile per interrompere un programma con Control-C, e può mascherare altri problemi. Se si desidera rilevare tutte le eccezioni che segnalano errori di programma, utilizzare tranne Eccezione: (nuda eccetto che è equivalente ad eccezione di BaseException:).

Una buona regola è quella di limitare l'uso della nuda 'tranne' clausole di due casi:

Se il gestore di eccezioni sarà stampare o registrazione della traceback; almeno l'utente sarà consapevole che si è verificato un errore.

Se il codice deve eseguire qualche operazione di pulizia, ma consente di propagare l'eccezione verso l'alto con aumento. provare ... finalmente può essere un modo migliore per gestire questo caso.

Come fare in questo modo?

+0

Non capisco cosa stai chiedendo. Quali tipi di eccezioni * vuoi * gestire? – BrenBarn

+1

quali eccezioni potrebbero essere sollevate dalla tua funzione? – haifzhan

+2

'tranne Eccezione:' è diverso da nullo 'eccetto: '. Quella sezione PEP8 avverte su quest'ultimo, stai facendo il primo. – roippi

risposta

13

La guida PEP8 citata suggerisce che è possibile utilizzare un'eccezione nel caso in cui si stiano registrando gli errori. Penserei che dovresti coprire tutte le eccezioni che puoi/sapere come gestire e quindi registrare il resto e pass, ad es.

import logging 

list_of_functions = [f_a,f_b,f_c] 
for current_function in list_of_functions: 
    try: 
     current_function() 
    except KnownException: 
     raise 
    except Exception as e: 
     logging.exception(e) 
+0

'tranne KeyboardInterrupt: raise' è strettamente inutile qui. 'KeyboardInterrupt' non verrà mai catturato da' except Exception' perché 'KeyboardInterrupt' deriva da' BaseException', non 'Exception'. – roippi

+0

Volevo solo un esempio di un'eccezione nota, non rendersi conto che 'KeyboardInterrupt' è un cattivo esempio. L'ho cambiato in qualche generico 'KnownException' ... –

+0

Un nudo tranne che è più adatto qui. 'logging.exception()' registrerà automaticamente l'errore e il traceback. – user2923419

0

Forse intendi che ogni funzione può sollevare eccezioni diverse? Quando si nomina il tipo di eccezione nella clausola except, può essere qualsiasi nome che faccia riferimento a un'eccezione, non solo il nome della classe.

es.

def raise_value_error(): 
    raise ValueError 

def raise_type_error(): 
    raise TypeError 

def raise_index_error(): 
    doesnt_exist 

func_and_exceptions = [(raise_value_error, ValueError), (raise_type_error, TypeError), 
    (raise_index_error, IndexError)] 

for function, possible_exception in func_and_exceptions: 
    try: 
     function() 
    except possible_exception as e: 
     print("caught", repr(e), "when calling", function.__name__) 

stampe:

caught ValueError() when calling raise_value_error 
caught TypeError() when calling raise_type_error 
Traceback (most recent call last): 
    File "run.py", line 14, in <module> 
    function() 
    File "run.py", line 8, in raise_index_error 
    doesnt_exist 
NameError: name 'doesnt_exist' is not defined 

Certo che ti lascia con non sapendo cosa fare quando si verifica ciascuna eccezione. Ma dal momento che vuoi solo ignorarlo e continuare, non è un problema.

1
__author__ = 'xray' 
# coding: utf8 
from wiki_baike import url_manager, html_downloader, html_parser, html_outputer 
import logging 

class SpiderMain(object): 
    def __init__(self): 
     self.url = url_manager.UrlManager() 
     self.downloader = html_downloader.HtmlDownloader() 
     self.parser = html_parser.HtmlParser() 
     self.outputer = html_outputer.HtmlOutputer() 

    def craw(self, root_url): 
     count = 1 
     self.urls.add_new_url(root_url) 
     while self.urls.has_new_url(): 
      try: 
       new_url = self.urls.get_new_url() 
       print 'craw %d : %s' % (count, new_url) 
       html_cont = self.downloader.download(new_url) 
       new_urls, new_data = self.parser.parse(new_url, html_cont) 
       self.urls.add_new_urls(new_urls) 
       self.outputer.collect_data(new_data) 
       if count == 1000: 
        break 
       count += 1 
      except Exception as e: 
       logging.exception(e) 
       print 'error' 
     self.outputer.output_html() 

    if __name__=='__main__': 
    root_url = 'http://baike.baidu.com/view/21087.html' 
    # root_url = 'https://rollbar.com/docs/' 
    obj_spider = SpiderMain() 
    obj_spider.craw(root_url) 
+1

In che modo risponde a questa domanda? –

+2

Non spiega quale sia il problema, e non affronta la domanda, vale a dire come rilevare solo le eccezioni desiderate. –

0

//youtrack.jetbrains.com/problema/PY-9715

PY-9715 incoerenti "le clausole di eccezione troppo ampia" ispezione [ispezione "troppo ampia clausole di eccezione"] [1]

//legacy.python .org/dev/PEP/pep-0348/

BaseException

La superclasse che tutte le eccezioni mu st eredita da. Il suo nome era scelto per riflettere che si trova alla base della gerarchia di eccezioni pur essendo un'eccezione stessa. "Raisable" è stato considerato come un nome, è stato trasmesso perché il suo nome non riflette correttamente il fatto che è un'eccezione stessa.

L'ereditarietà diretta di BaseException non è prevista, e sarà scoraggiato per il caso generale. La maggior parte delle eccezioni definite dall'utente dovrebbe invece ereditare dall'eccezione. Ciò consente di intercettare Eccezione su e continuare a lavorare nel caso comune di rilevamento di tutte le eccezioni che devono essere rilevate da . L'ereditarietà diretta di BaseException deve essere solo eseguita nei casi in cui si desidera una categoria di eccezione completamente nuova.

Tuttavia, per i casi in cui tutte le eccezioni devono essere catturate ciecamente, tranne BaseException funzionerà.

[1] http://i.stack.imgur.com/8UByz.png

//youtrack.jetbrains.com/issue/PY-9715

//legacy.python.org/dev/peps/pep-0348/