Bir değişkene traceback / sys.exc_info () değerleri nasıl kaydedilir?


127

Hatanın adını ve geri izleme ayrıntılarını bir değişkene kaydetmek istiyorum. İşte benim girişimim.

import sys
try:
    try:
        print x
    except Exception, ex:
        raise NameError
except Exception, er:
    print "0", sys.exc_info()[0]
    print "1", sys.exc_info()[1]
    print "2", sys.exc_info()[2]

Çıktı:

0 <type 'exceptions.NameError'>
1 
2 <traceback object at 0xbd5fc8>

Istenilen çıktı:

0 NameError
1
2 Traceback (most recent call last):
  File "exception.py", line 6, in <module>
    raise NameError

PS Bunun traceback modülü kullanılarak kolayca yapılabileceğini biliyorum, ancak burada sys.exc_info () [2] nesnesinin kullanımını bilmek istiyorum.


Sys.exc_info () [x] .__ str __ () yazdırmayı denediniz mi?
zmbq

3
Programınızda neler olup bittiğini yanlış anlamış olabilirsiniz: "sys.exc_info () [2] nesnesi" olarak ifade ettiğiniz şey, izleme nesnesinin bir örneğidir (= izleme modülünü zaten kullanıyorsunuz). Artık, traceback modülündeki yardımcı işlevleri kullanmadan bu nesneyi işleyebilirsiniz, ancak bu, onu hala kullanmakta olduğunuz gerçeğini değiştirmez. :)
mac

1
Bu yüzden @mac lütfen yardımcı işlevi kullanarak veya kullanmadan bu nesnedeki değere erişmeme yardım edin.
codersofthedark

1
@dragosrsupercool - Aşağıdaki cevabımda bahsettiğim gibi, geri izleme belgelerine bakmalısınız . Verilerin metin olarak nasıl alınacağına dair bir örnek verdim, ancak nesnenin istisna adını, kodun satırını vb. Ayıklamanıza izin veren başka yöntemleri de var ... doğru olan, gerçekten, değer sonradan ...
mac

1
Başka bir soruya verdiğim yanıt , ayrıntıları göstermeye yardımcı olabilir - bağlantılarla! Hazır dizeler için, standart kitaplık geri izleme modülü uygun görünüyor. Ayrıntıları almak istiyorsanız, <python install path>/Lib/traceback.pydaha fazla bilgi için kaynağı ( ) okuyun .
pythonlarry

Yanıtlar:


180

Ben böyle yaparım:

>>> import traceback
>>> try:
...   int('k')
... except:
...   var = traceback.format_exc()
... 
>>> print var
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError: invalid literal for int() with base 10: 'k'

Bununla birlikte , daha sonra değişkeninizi nasıl işlemek istediğinize bağlı olarak daha uygun yöntemler bulabileceğiniz için geri izleme belgelerine bir göz atmalısınız ...


1
Traceback modülü kullanmadan bir yöntem arıyordum. Bu nesne referansından geriye dönük ayrıntıları yazdırabileceğimiz bir yol var mı? sys.exc_info () [2]
codersofthedark

Doğru, bu yüzden sys.exc_info () [2] .format_exc () gibi bir şey yapabileceğimizi düşündüm, ama bu işe yaramıyor .. Bu nedenle, sys.exc_info () trace-back nesnesinden nasıl değer çıkarabilirim merak ediyorum. [2]. Herhangi bir fikir?
codersofthedark

1
sys.exc_info () [2] .tb_text takip hatası veriyor -> AttributeError: 'traceback' nesnesinin 'tb_text' özniteliği yok
codersofthedark

4
@dragosrsupercool - sys.exc_info()[2].tb_frame.f_code.co_names[3], ama hiçbir anlamı yok ... tracebackStandart kitaplıkta çağrılan bir modül varsa , bunun bir nedeni var ... :)
mac

2
@codersofthedark traceback.format_exception(*sys.exc_info())bunu yapmanın yolu. Ama bu işlevsel olarak eşdeğerdir traceback.format_exc().
wizzwizz4

25

sys.exc_info (), üç değere (tür, değer, izleme) sahip bir demet döndürür.

  1. Burada tür, işlenmekte olan İstisnanın istisna türünü alır
  2. değer, istisna sınıfının yapıcısına iletilen argümanlardır
  3. traceback, istisnanın meydana geldiği yer gibi yığın bilgilerini içerir.

Örneğin, aşağıdaki programda

try:

    a = 1/0

except Exception,e:

    exc_tuple = sys.exc_info()

Şimdi demeti yazdırırsak değerler bu olacaktır.

  1. exc_tuple [0] değeri " ZeroDivisionError " olacaktır
  2. exc_tuple [1] değeri " tamsayı bölme veya sıfıra göre modulo " olacaktır (Dize, istisna sınıfına parametre olarak geçirilir)
  3. exc_tuple [2] değeri " geri izleme nesnesi (bazı bellek adreslerinde) " olacaktır

Yukarıdaki ayrıntılar, istisnayı dize biçiminde yazdırarak da alınabilir.

print str(e)

Python3 için exc_tuple [1] (aka değer), "Parametre olarak geçirilen dizge" değil, istisnanın örneğidir . Bakınız: docs.python.org/3/library/sys.html#sys.exc_info
Shi

"E: İstisna hariç" olması gerekmez mi?
Henrik

20

traceback.extract_stack()Modül ve işlev adlarına ve hat numaralarına kolay erişim istiyorsanız kullanın .

''.join(traceback.format_stack())Yalnızca traceback.print_stack()çıktıya benzeyen bir dizge istiyorsanız kullanın .

Unutma ki, ''.join()seninle bile çok satırlı bir dize alacaksınız, çünkü öğeleri format_stack()içerir \n. Aşağıdaki çıktıya bakın.

Unutma import traceback.

İşte buradan çıktı traceback.extract_stack(). Okunabilirlik için biçimlendirme eklendi.

>>> traceback.extract_stack()
[
   ('<string>', 1, '<module>', None),
   ('C:\\Python\\lib\\idlelib\\run.py', 126, 'main', 'ret = method(*args, **kwargs)'),
   ('C:\\Python\\lib\\idlelib\\run.py', 353, 'runcode', 'exec(code, self.locals)'),
   ('<pyshell#1>', 1, '<module>', None)
]

İşte buradan çıktı ''.join(traceback.format_stack()). Okunabilirlik için biçimlendirme eklendi.

>>> ''.join(traceback.format_stack())
'  File "<string>", line 1, in <module>\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 126, in main\n
       ret = method(*args, **kwargs)\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 353, in runcode\n
       exec(code, self.locals)\n  File "<pyshell#2>", line 1, in <module>\n'

4

Özel durum nesnesini veya geri izleme nesnesini istisna işleyiciden çıkarırken dikkatli olun, çünkü bu döngüsel referanslara neden gc.collect()olur ve toplanamaz. Bu görünür traceback nesne doğru zamanda temizlenir ve hatta açık bir çağrı almaz ipython / jupyter dizüstü ortamında belirli bir problemin olması gc.collect()halinde finallybölümünde hiçbir şey yapmaz. Ve bu nedenle belleğini geri alamayan bazı büyük nesneleriniz varsa bu büyük bir sorundur (örneğin, bu çözümün kurtarılması için çekirdeğin tamamen yeniden başlatılmasını gerektirmeyen bellek dışı CUDA istisnaları).

Genel olarak, geri izleme nesnesini kaydetmek istiyorsanız, onu aşağıdaki locals()gibi referanslardan temizlemeniz gerekir :

import sys, traceback, gc
type, val, tb = None, None, None
try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
# some cleanup code
gc.collect()
# and then use the tb:
if tb:
    raise type(val).with_traceback(tb)

Jupyter not defteri durumunda, bunu en azından istisna işleyicinin içinde yapmanız gerekir:

try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
    raise type(val).with_traceback(tb)
finally:
    # cleanup code in here
    gc.collect()

Python 3.7 ile test edilmiştir.

ps ipython veya jupyter notebook env ile ilgili sorun, traceback'i %tbkurtaran ve daha sonra herhangi bir noktada kullanılabilir hale getiren bir sihire sahip olmasıdır. Ve sonuç olarak locals(), izlemeye katılan tüm çerçevelerdeki herhangi biri, dizüstü bilgisayar çıkıncaya kadar serbest bırakılmayacak veya başka bir istisna, önceden depolanan geri izlemenin üzerine yazılacaktır. Bu çok sorunlu. İzi, çerçevelerini temizlemeden saklamamalıdır. Düzeltme burada gönderildi .


3

Nesne, Exception.with_traceback()işlevde bir parametre olarak kullanılabilir :

except Exception as e:
    tb = sys.exc_info()
    print(e.with_traceback(tb[2]))
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.