python: Ne tür bir istisnanın oluştuğunu nasıl bilebilirim?


230

Ana program tarafından çağrılan bir fonksiyon var:

try:
    someFunction()
except:
    print "exception happened!"

ancak işlevin yürütülmesinin ortasında istisna yaratır, bu yüzden exceptparçaya atlar .

someFunction()İstisnanın gerçekleşmesine neden olan şeyde tam olarak ne olduğunu nasıl görebilirim ?


9
Bir daha asla çıplak asla kullanmayın except:(çıplak olmadan raise), hariç belki tercihen değil o programın başına bir kez, ve.
Mike Graham

exceptİstisna türünü kontrol etmeniz gerekmeyen birden fazla cümle kullanırsanız , genellikle belirli bir istisna türüne göre hareket etmek için yapılan budur.
Rik Poggi

3
İstisna türünü önemsiyorsanız, bunun nedeni mantıksal olarak ne tür istisnaların oluşabileceğini düşündüğünüzdür.
Karl Knechtel

3
İçinde exceptistisna aracılığıyla kullanılabilir blok sys.exc_info()- fonksiyonu Bu fonksiyon şu anda işlenen özel durum hakkında bilgi vermek üç değerden bir demet döndürür.
Piotr Dobrogost

Yanıtlar:


384

Diğer yanıtlar, genel istisnaları yakalamamanız gerektiğine işaret ediyor, ancak kimse size nedenini söylemek istemiyor gibi görünüyor, bu da “kuralı” ne zaman kırabileceğinizi anlamak için gereklidir. İşte bir açıklama. Temel olarak, gizlememeniz için:

Dolayısıyla, bunlardan hiçbirini yapmaya özen gösterdiğiniz sürece, genel istisnayı yakalamak sorun olmaz. Örneğin, istisna hakkında kullanıcıya aşağıdaki gibi başka bir yol sağlayabilirsiniz:

  • İstisnaları bir GUI'de iletişim kutusu olarak sunma
  • Çok iş parçacıklı veya çok işlemcili bir uygulamada, bir iş parçacığı veya işleminden denetim iş parçacığına veya işleme özel durumlar aktarma

Peki genel istisna nasıl yakalanır? Birkaç yol var. Sadece istisna nesnesini istiyorsanız, bunu şu şekilde yapın:

try:
    someFunction()
except Exception as ex:
    template = "An exception of type {0} occurred. Arguments:\n{1!r}"
    message = template.format(type(ex).__name__, ex.args)
    print message

Make emin message sert kaçırılması şekilde kullanıcının dikkati getirilir! Mesaj çok sayıda mesaja gömüldüyse, yukarıda gösterildiği gibi yazdırmak yeterli olmayabilir. Kullanıcıların dikkatini çekmemek, tüm istisnaları yutmak anlamına gelir ve bu sayfadaki cevapları okuduktan sonra gelmeniz gereken bir izlenim varsa, bu iyi bir şey değildir . raiseDışındaki bloğun bir ifade ile sonlandırılması , yakalanan istisnayı şeffaf bir şekilde yeniden karşılaştırarak sorunu çözecektir.

Yukarıdakiler ile except:herhangi bir argüman olmadan kullanım arasındaki fark iki yönlüdür:

  • Bir çıplak except:size incelemeniz için istisna nesnesini vermez
  • İstisnalar SystemExit, KeyboardInterruptve GeneratorExitgenel olarak ne istediğinizi Yukarıdaki kodla tarafından yakalanmış değil. İstisna hiyerarşisine bakın .

İstisnayı yakalamazsanız aldığınız yığın izlemesini de istiyorsanız, bunu şu şekilde alabilirsiniz (yine de yan tümce içinde):

import traceback
print traceback.format_exc()

loggingModülü kullanırsanız, istisnayı günlüğe (bir mesajla birlikte) şu şekilde yazdırabilirsiniz:

import logging
log = logging.getLogger()
log.exception("Message for you, sir!")

Daha derine inmek ve yığını incelemek, değişkenlere vb. Bakmak istiyorsanız , hariç blok içindeki modülün post_mortemişlevini kullanın pdb:

import pdb
pdb.post_mortem()

Bu son yöntemi böcekleri avlarken çok değerli buldum.


1
traceback.print_exc () daha karmaşık olan "" ile aynı şeyi yapar.
Gurgeh

1
@Gurgeh Evet, ancak yazdırmak mı yoksa bir dosyaya kaydetmek mi, yoksa oturum açmak mı veya onunla başka bir şey yapmak mı istediğini bilmiyorum.
Lauritz V. Thaulow

Düşürmedim, ama şunu söyleyebilirim çünkü başlangıçta büyük bir yağ yakmanız gerekiyordu, buna ihtiyacın yok, ama işte nasıl yapılacağı . Ve belki de genel İstisna'yı yakalamanızı önerdiğiniz için.
Rik Poggi

10
@Rik Bence tüm bunlara ihtiyacın olabilir . Örneğin, GUI ve arka uç içeren bir programınız varsa ve programınızın yığın izlemesinden çıkmasını sağlamak yerine arka uçtaki tüm istisnaları GUI iletileri olarak sunmak istiyorsanız. Böyle bir durumda, genel İstisnayı yakalamanız, iletişim kutusu için bir geri izleme metni oluşturmanız, istisnayı da günlüğe kaydetmeniz ve hata ayıklama modunda ise ölüm sonrası girmeniz gerekir.
Lauritz V. Thaulow

18
@RikPoggi: Saf düşünme. Başkasının kodundan istisnaları yakalamanız gerektiğinde ve hangi istisnaların ortaya çıkacağını bilmediğiniz birçok makul koşul vardır.
stackoverflowuser2010

63

İstisna nesnesinin ait olduğu sınıfın adını alın:

e.__class__.__name__

ve print_exc () fonksiyonunun kullanılması, herhangi bir hata mesajı için gerekli bilgi olan yığın izlemesini de yazdıracaktır.

Bunun gibi:

from traceback import print_exc

class CustomException(Exception): pass

try:
    raise CustomException("hi")
except Exception, e:
    print 'type is:', e.__class__.__name__
    print_exc()
    # print "exception happened!"

Bu şekilde çıktı alacaksınız:

type is: CustomException
Traceback (most recent call last):
  File "exc.py", line 7, in <module>
    raise CustomException("hi")
CustomException: hi

Ve baskı ve analizden sonra, kod istisnayı işlememeye ve sadece yürütmeye karar verebilir raise:

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except Exception, e:
    if e.__class__ == CustomException:
        print 'special case of', e.__class__.__name__, 'not interfering'
        raise
    print "handling exception"

Çıktı:

special case of CustomException not interfering

Ve tercüman istisna yazdırır:

Traceback (most recent call last):
  File "test.py", line 9, in <module>
    calculate()
  File "test.py", line 6, in calculate
    raise CustomException("hi")
__main__.CustomException: hi

raiseOrijinal istisna sonra çağrı yığını daha ilerlemeye devam ediyor. ( Olası tuzağa dikkat edin ) Yeni bir istisna getirirseniz, yeni (daha kısa) yığın izini taşır.

from traceback import print_exc

class CustomException(Exception): pass

def calculate():
    raise CustomException("hi")

try:
    calculate()
except Exception, e:
    if e.__class__ == CustomException:
        print 'special case of', e.__class__.__name__, 'not interfering'
        #raise CustomException(e.message)
        raise e
    print "handling exception"

Çıktı:

special case of CustomException not interfering
Traceback (most recent call last):
  File "test.py", line 13, in <module>
    raise CustomException(e.message)
__main__.CustomException: hi    

Geri izlemenin, orijinal istisnanın kaynağı olan calculate()satırdan işlevi nasıl içermediğine dikkat edin .9e


Eğer bir dize olarak Traceback saklamak istiyorsanız, kullanabileceğiniz traceback.format_exc()yanı
Stevoisiak

1
e.__class__.__name__bu type(e).__name__yukarıdaki cevabın önerdiği ile aynı mı?
information_interchange

1
@ info_interchange evet. Soru ve kabul edilen cevap içeriği zaman içinde tamamen değişti. Diğer katılımcılara SO makineleri tarafından bildirilmemesi utanç verici :(
Alex

14

try: ... exceptAşırı geniş olduğu için genellikle olası tüm istisnaları yakalamamalısınız . Herhangi bir nedenle gerçekleşmesi beklenenleri yakalayın. Gerçekten gerekiyorsa, örneğin hata ayıklama sırasında bazı sorunlar hakkında daha fazla bilgi edinmek istiyorsanız,

try:
    ...
except Exception as ex:
    print ex # do whatever you want for debugging.
    raise    # re-raise exception.

17
Burada "asla" kelimesinin kullanımı hiç bu kadar yanlış olmamıştı. Kullandığım try: ... except Exception:pek çok şey, şebekeye bağlı kütüphanelerin örn kullanımı veya ona gönderilen garip şeyler alabilirsiniz veri masöz etrafında. Doğal olarak ben de uygun günlük kaydı var. Bu, giriş verilerinde tek bir hata olması durumunda programın çalışmaya devam etmesini sağlamak için çok önemlidir.
13'te

3
Hiç kullanarak e-posta gönderirken ortaya çıkabilecek tüm istisnaları yakalamaya çalıştınız smtplibmı?
linusg

1
Tüm istisnaları yakalamanın gerekli olduğu bazı özel durumlar olabilir, ancak genel düzeyde beklediğiniz şeyi yakalamanız gerekir, böylece beklemediğiniz hataları yanlışlıkla gizlemezsiniz. İyi kayıt elbette iyi bir fikirdir.
hochl

1
Tüm istisnaları yakalamak son derece makul. Bir üçüncü taraf kütüphanesi arıyorsanız, bu kütüphanede hangi istisnaların ortaya çıkacağını bilemeyebilirsiniz. Böyle bir durumda, tek istisna, tüm istisnaları yakalamak, örneğin bir dosyada oturum açmaktır.
stackoverflowuser2010

Tamam, haklısın, cevabı yakalamak için geçerli kullanım örnekleri olduğunu açıkça belirtmek için cevabımı yeniden yazacağım.
hochl

10

somefunctionÇok kötü kodlanmış eski bir işlev olmadığı sürece , sorduğunuz şeye ihtiyacınız olmamalıdır.

exceptFarklı istisnaları farklı şekillerde ele almak için birden fazla yan tümce kullanın :

try:
    someFunction()
except ValueError:
    # do something
except ZeroDivision:
    # do something else

Ana nokta, genel istisnayı değil, sadece ihtiyacınız olanları yakalamanız gerektiğidir. Beklenmedik hataları veya hataları gölgelemek istemediğinizden eminim.


8
Üçüncü taraf bir kütüphane kullanıyorsanız, içinde hangi istisnaların doğacağını bilemeyebilirsiniz. Hepsini nasıl tek tek yakalayabilirsiniz?
stackoverflowuser2010

8

Çoğu cevap except (…) as (…):sözdizimi (haklı olarak) işaret eder, ancak aynı zamanda kimse filin sys.exc_info()işlev gördüğü odada bir fil hakkında konuşmak istemez . Gönderen belgelere ait sys modülü (vurgu benim):

Bu işlev, işlenmekte olan kural dışı durum hakkında bilgi veren üç değerden oluşan bir demet döndürür.
(…)
Yığın üzerinde herhangi bir istisna ele alınmıyorsa, üç Yok değeri içeren bir demet döndürülür. Aksi takdirde, döndürülen değerler (tip, değer, geri izleme) şeklindedir. Anlamları: type, işlenen istisnanın türünü alır (BaseException'ın bir alt sınıfı); değer kural dışı durum örneğini (kural dışı durum türünün bir örneği) alır; traceback, çağrı yığınını istisnanın ilk gerçekleştiği noktada kapsülleyen bir geri izleme nesnesi alır (Referans Kılavuzuna bakın).

Bence ne tür bir istisnanın meydana geldiğini nasıl bilebilirim?sys.exc_info() Orijinal sorusuna en doğrudan cevap olarak değerlendirilebilir.


1
Bu, benim için doğru cevaptır, çünkü istisnanın ne olduğu sorununu çözer, bu yüzden çıplak yerine ne koymalıyım except. Sadece bütünlük uğruna, exctype, value = sys.exc_info()[:2]daha sonra üzerinde kullanılabilecek istisna türünü söyleyecektir except.
Ondrej Burkert

5

try: someFunction () dışında Exception, exc:

#this is how you get the type
excType = exc.__class__.__name__

#here we are printing out information about the Exception
print 'exception type', excType
print 'exception msg', str(exc)

#It's easy to reraise an exception with more information added to it
msg = 'there was a problem with someFunction'
raise Exception(msg + 'because of %s: %s' % (excType, exc))

-1'in kullanımı exc.__class__.__name__Alex'in cevabında zaten önerilmişti - stackoverflow.com/a/9824060/95735
Piotr Dobrogost

3

Bu yanıtlar hata ayıklama için iyidir, ancak istisnayı programlı olarak test etmek isinstance(e, SomeException)için, alt sınıfları da test ettiği için kullanışlı olabilir SomeException, böylece istisna hiyerarşileri için geçerli işlevsellik oluşturabilirsiniz.


1

İstisnalarımı şu şekilde ele alıyorum. Fikir, bu kolaysa sorunu çözmeyi denemek ve daha sonra mümkünse daha arzu edilen bir çözüm eklemektir. İstisna oluşturan kodda veya kodun, noktaya yazılması gereken orijinal algoritmanın izini kaybettiği sorunu çözmeyin. Ancak, sorunu çözmek için gereken verileri iletin ve sorunu oluşturan kodun dışında çözememeniz durumunda lambda döndürün.

path = 'app.p'

def load():
    if os.path.exists(path):
        try:
            with open(path, 'rb') as file:
                data = file.read()
                inst = pickle.load(data)
        except Exception as e:
            inst = solve(e, 'load app data', easy=lambda: App(), path=path)()
    else:
        inst = App()
    inst.loadWidgets()

# e.g. A solver could search for app data if desc='load app data'
def solve(e, during, easy, **kwargs):
    class_name = e.__class__.__name__
    print(class_name + ': ' + str(e))
    print('\t during: ' + during)
    return easy

Şimdilik, uygulamamın amacına teğetsel olarak düşünmek istemediğim için, karmaşık çözümler eklemedim. Ancak gelecekte, olası çözümler hakkında daha fazla bilgi sahibi olduğumda (uygulama daha fazla tasarlandığından), dizine eklenmiş bir çözüm sözlüğü ekleyebilirim during.

Gösterilen örnekte bir çözüm, 'app.p' dosyasının yanlışlıkla silinip silinmediğini, başka bir yerde saklanan uygulama verilerini aramak olabilir.

Şimdilik, istisna işleyiciyi yazmak akıllı bir fikir olmadığından (henüz çözmenin en iyi yollarını bilmiyoruz, çünkü uygulama tasarımı gelişecek), basitçe çalıştığımız gibi davranmak için kolay düzeltmeyi döndürüyoruz uygulamayı ilk kez (bu durumda).


0

Lauritz'in cevabına eklemek için, istisna işleme için bir dekoratör / sarmalayıcı oluşturdum ve hangi istisna türünün sarmalayıcı günlüklerini oluşturdum.

class general_function_handler(object):
    def __init__(self, func):
        self.func = func
    def __get__(self, obj, type=None):
        return self.__class__(self.func.__get__(obj, type))
    def __call__(self, *args, **kwargs):
        try:
            retval = self.func(*args, **kwargs)
        except Exception, e :
            logging.warning('Exception in %s' % self.func)
            template = "An exception of type {0} occured. Arguments:\n{1!r}"
            message = template.format(type(e).__name__, e.args)
            logging.exception(message)
            sys.exit(1) # exit on all exceptions for now
        return retval

Bu, bir sınıf yönteminde veya dekoratörle bağımsız bir işlevde çağrılabilir:

@general_function_handler

Tam örnek için bloguma bakın: http://ryaneirwin.wordpress.com/2014/05/31/python-decorators-and-exception-handling/


0

Lauritz'in önerdiği şekilde başlayabilirsiniz:

except Exception as ex:

ve sonra sadece print exbeğenmek için:

try:
    #your try code here
except Exception as ex:
    print ex

Cevabınızın yalnız kalması için biraz ayrıntı verebilir misiniz?
GHC

1
emin: yakalanan istisnayı şu şekilde yazdırabilirsiniz: deneyin: #Burada denediğiniz kodu hariç Ex: ex ex olarak yazdır şimdi hata yazdırılacak
Gura

-2

Gerçek istisna aşağıdaki şekilde yakalanabilir:

try:
    i = 1/0
except Exception as e:
    print e

İstisnalar hakkında daha fazla bilgiyi Python Tutorial'dan öğrenebilirsiniz .


-2

Sorunuz: "Bazı istisnaların gerçekleşmesine neden olan someFunction () öğesinde tam olarak ne olduğunu nasıl görebilirim?"

Bana öyle geliyor ki, üretim kodunda öngörülmeyen istisnaların nasıl ele alınacağını sormuyorsunuz (varsayıldığı gibi), ancak geliştirme sırasında belirli bir istisnanın neye neden olduğunu nasıl bulacağınızı öğrenin.

En kolay yol, yakalanmamış istisnanın oluştuğu yerde durdurulabilen, tercihen çıkmayan bir hata ayıklayıcı kullanmaktır, böylece değişkenleri inceleyebilirsiniz. Örneğin, Eclipse açık kaynak IDE'deki PyDev bunu yapabilir. Eclipse o etkinleştirmek ayıklama perspektifi açın seçmek için Manage Python Exception Breakpointsde Runmenü ve kontrol Suspend on uncaught exceptions.


-4

Sadece Python'un yazdırdığı istisnayı ve izlemeyi yakalamaktan kaçının.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.