Làm cách nào để lưu các giá trị tracBack / sys.exc_info () trong một biến?


127

Tôi muốn lưu tên của lỗi và các chi tiết truy nguyên vào một biến. Đây là nỗ lực của tôi.

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]

Đầu ra:

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

Sản phẩm chất lượng:

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

PS Tôi biết điều này có thể được thực hiện dễ dàng bằng cách sử dụng mô-đun tracBack, nhưng tôi muốn biết cách sử dụng đối tượng sys.exc_info () [2] tại đây.


Bạn đã thử in sys.exc_info () [x] .__ str __ () chưa?
zmbq

3
Bạn có thể đã hiểu nhầm những gì đang diễn ra trong chương trình của mình: những gì bạn gọi là "sys.exc_info () [2] object" là một ví dụ của đối tượng tracBack (= bạn đã sử dụng mô-đun tracBack rồi). Bây giờ, bạn có thể thao tác với đối tượng đó mà không cần sử dụng các hàm trợ giúp trong mô-đun truy nguyên, nhưng điều đó không thay đổi thực tế là bạn vẫn đang sử dụng nó. :)
mac

1
Vì vậy, @mac vui lòng giúp tôi sử dụng truy cập giá trị từ đối tượng này có hoặc không sử dụng chức năng trợ giúp.
codersofthedark

1
@dragosrsupercool - Như tôi đã đề cập trong câu trả lời của tôi dưới đây, bạn nên xem tài liệu truy nguyên . Tôi đã cung cấp một ví dụ về cách truy xuất dữ liệu bằng văn bản, nhưng có các phương thức khác của đối tượng cho phép bạn trích xuất tên ngoại lệ, hàng mã, v.v ... một cách đúng thực sự phụ thuộc vào cách bạn muốn thao tác giá trị sau đó ...
mac

1
Câu trả lời của tôi cho một câu hỏi khác có thể giúp minh họa các chi tiết - với các liên kết! Đối với các chuỗi đóng hộp, mô-đun truy nguyên thư viện tiêu chuẩn có vẻ ổn. Nếu bạn muốn biết chi tiết, hãy đọc nguồn ( <python install path>/Lib/traceback.py) để biết thêm thông tin.
pythonlarry

Câu trả lời:


180

Đây là cách tôi làm điều đó:

>>> 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'

Tuy nhiên, bạn nên xem tài liệu theo dõi , vì bạn có thể thấy có các phương thức phù hợp hơn, tùy thuộc vào cách bạn muốn xử lý biến của mình sau đó ...


1
Tôi đã tìm kiếm một phương pháp mà không sử dụng mô-đun trac trở lại. Có cách nào đó chúng ta có thể in chi tiết theo dõi từ tham chiếu đối tượng này không? sys.exc_info () [2]
codersofthedark

Đúng vậy, đó là lý do tại sao tôi nghĩ rằng chúng ta có thể làm một cái gì đó như sys.exc_info () [2] .format_exc (), nhưng điều này không hoạt động .. Vì vậy, tôi tự hỏi làm thế nào tôi có thể trích xuất giá trị từ đối tượng theo dõi sys.exc_info () [2]. Bất kỳ ý tưởng?
codersofthedark

1
sys.exc_info () [2] .tb bản có lỗi theo dõi -> AttributionError: đối tượng 'tracBack' không có thuộc tính 'tb bản'
codersofthedark

4
@dragosrsupercool - sys.exc_info()[2].tb_frame.f_code.co_names[3], nhưng chẳng có nghĩa lý gì cả ... Nếu có một mô-đun được gọi tracebacktrong thư viện chuẩn, có một lý do cho nó ... :)
mac

2
@codersofthedark traceback.format_exception(*sys.exc_info())là cách để làm điều đó. Nhưng đó là chức năng tương đương với traceback.format_exc().
wizzwizz4

25

sys.exc_info () trả về một tuple với ba giá trị (loại, giá trị, truy nguyên).

  1. Ở đây loại có loại ngoại lệ của Ngoại lệ được xử lý
  2. giá trị là các đối số đang được truyền cho hàm tạo của lớp ngoại lệ
  3. truy nguyên chứa thông tin ngăn xếp như nơi xảy ra ngoại lệ, v.v.

Ví dụ: Trong chương trình sau

try:

    a = 1/0

except Exception,e:

    exc_tuple = sys.exc_info()

Bây giờ Nếu chúng ta in tuple, các giá trị sẽ là cái này.

  1. Giá trị exc_tuple [0] sẽ là " ZeroDivisionError "
  2. Giá trị exc_tuple [1] sẽ là " chia số nguyên hoặc modulo bằng 0 " (Chuỗi được truyền dưới dạng tham số cho lớp ngoại lệ)
  3. Giá trị exc_tuple [2] sẽ là " đối tượng theo dõi tại (một số địa chỉ bộ nhớ) "

Các chi tiết trên cũng có thể được tìm nạp bằng cách in ngoại lệ ở định dạng chuỗi.

print str(e)

Đối với Python3, exc_tuple [1] (còn gọi là giá trị) là trường hợp ngoại lệ, không phải là "Chuỗi được truyền dưới dạng tham số". Xem: docs.python.org/3/l Library / sys.html
Jinghao Shi

Không phải là "ngoại trừ ngoại lệ như e:"?
Henrik

20

Sử dụng traceback.extract_stack()nếu bạn muốn truy cập thuận tiện vào tên mô-đun và chức năng và số dòng.

Sử dụng ''.join(traceback.format_stack())nếu bạn chỉ muốn một chuỗi trông giống như traceback.print_stack()đầu ra.

Lưu ý rằng ngay cả với ''.join()bạn sẽ có được một chuỗi nhiều dòng, vì các thành phần format_stack()có chứa \n. Xem đầu ra dưới đây.

Nhớ nhé import traceback.

Đây là đầu ra từ traceback.extract_stack(). Định dạng được thêm vào để dễ đọc.

>>> 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)
]

Đây là đầu ra từ ''.join(traceback.format_stack()). Định dạng được thêm vào để dễ đọc.

>>> ''.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

Hãy cẩn thận khi bạn lấy đối tượng ngoại lệ hoặc đối tượng truy nguyên ra khỏi trình xử lý ngoại lệ, vì điều này gây ra các tham chiếu vòng tròn và gc.collect()sẽ không thu thập được. Điều này dường như là một vấn đề cụ thể trong môi trường máy tính xách tay ipython / jupyter nơi đối tượng truy nguyên không được xóa đúng lúc và ngay cả một cuộc gọi rõ ràng gc.collect()trong finallyphần cũng không có gì. Và đó là một vấn đề lớn nếu bạn có một số đối tượng khổng lồ không lấy lại được bộ nhớ của chúng vì điều đó (ví dụ: CUDA ra khỏi bộ nhớ ngoại lệ rằng giải pháp này yêu cầu khởi động lại hạt nhân hoàn toàn để phục hồi).

Nói chung nếu bạn muốn lưu đối tượng theo dõi, bạn cần xóa nó khỏi các tham chiếu đến locals(), như vậy:

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)

Trong trường hợp máy tính xách tay jupyter, bạn phải làm điều đó ít nhất là bên trong trình xử lý ngoại lệ:

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()

Đã thử nghiệm với trăn 3.7.

Vấn đề với ipython hoặc jupyter notebook env là nó có %tbphép thuật giúp lưu lại dấu vết và làm cho nó có sẵn tại bất kỳ thời điểm nào sau đó. Và kết quả là bất kỳ locals()khung nào trong tất cả các khung tham gia truy xuất sẽ không được giải phóng cho đến khi sổ ghi chép thoát hoặc ngoại lệ khác sẽ ghi đè lên phần nền được lưu trữ trước đó. Điều này rất có vấn đề. Nó không nên lưu trữ truy nguyên không làm sạch khung của nó. Sửa lỗi gửi tại đây .


3

Đối tượng có thể được sử dụng như một tham số trong Exception.with_traceback()hàm:

except Exception as e:
    tb = sys.exc_info()
    print(e.with_traceback(tb[2]))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.