2010-01-11 28 views
19

Tôi tự hỏi làm thế nào tôi có thể bắt được bất kỳ đối tượng được nêu nào (nghĩa là loại không mở rộng Exception) và vẫn nhận được tham chiếu đến nó.Làm thế nào để bắt một ngoại lệ trong python và nhận được một tham chiếu đến ngoại lệ, KHÔNG biết loại?

Tôi bắt gặp mong muốn làm điều này khi sử dụng Jython. Khi gọi một phương thức Java, nếu phương pháp đó đặt ra một ngoại lệ, nó sẽ không mở rộng lớp Exception Python, vì vậy một khối như thế này sẽ không bắt nó:

try: 
    # some call to a java lib that raises an exception here 
except Exception, e: 
    # will never be entered 

tôi có thể làm điều này, nhưng sau đó tôi không có quyền truy cập vào đối tượng ngoại lệ được nâng lên.

Tôi có thể giải quyết vấn đề này bằng cách nhập loại ngoại lệ Java và bắt nó một cách rõ ràng, nhưng điều này gây khó khăn/không thể viết trình bao bọc/trang trí xử lý ngoại lệ chung.

Có cách nào để bắt ngoại lệ tùy ý và vẫn nhận được tham chiếu đến nó trong khối except không?

Tôi nên lưu ý rằng tôi hy vọng cho trang trí xử lý ngoại lệ mà tôi đang làm để có thể sử dụng được với các dự án Python, không chỉ với các dự án Jython. Tôi muốn tránh nhập java.lang.Exception vì điều đó chỉ làm cho nó chỉ là Jython. Ví dụ, tôi hình tôi có thể làm một cái gì đó như thế này (nhưng tôi đã không thử nó), nhưng tôi muốn tránh nó nếu tôi có thể.

try: 
    # some function that may be running jython and may raise a java exception 
except (Exception, java.lang.Exception), e: 
    # I imagine this would work, but it makes the code jython-only 
+0

Do những ngoại lệ này ít nhất có nguồn gốc từ BaseException? – Seth

Trả lời

33

Bạn có thể tham chiếu ngoại lệ bằng mô-đun sys. sys.exc_info là một bộ kiểu, thể hiện và truy nguyên.

import sys 

try: 
    # some call to a java lib that raises an exception here 
except: 
    instance = sys.exc_info()[1] 
+0

ah, sẽ cho nó một thử, cảm ơn! –

5

Chỉ cần cho bất cứ ai quan tâm đến ... Tôi đã dành một chút thứ thời gian thử nghiệm vì tôi muốn tìm hiểu làm thế nào để có được một stack trace thích hợp cho dù một ngoại lệ Python (BaseException trên thực tế, đó là lớp cơ sở) hoặc một java.lang.Throwable (lớp cơ sở java cho ngoại lệ, lỗi, vv) được ném ... mã này minh họa cách bắt tất cả các số dòng refs một cách chính xác.

import sys 
import traceback 
import java 

print "hello world" 

def custom_hook(type, exc, tb): 
    if isinstance(sys.exc_info()[ 1 ], java.lang.Throwable): 
    sys.stderr.write("AS JAVA:\n") 
    sys.exc_info()[ 1 ].printStackTrace() # java part 
    else: 
    sys.stderr.write("NO JAVA TRACE:\n") 
    sys.stderr.write("AS PYTHON:\n") 
    traceback.print_exc() 

# useful for custom exception handling! 
sys.excepthook = custom_hook 

def handle_exc(): 
# generate either a java.lang.Throwable (uncomment the next line and comment out "a = 16/0" 
# java.lang.String(None) 
# OR... a python-style BaseException: 
    a = 16/0 

class Task(java.lang.Runnable): 
    def run(self): 
    # NB the problem with all this stuff is that the Java stack trace shows 
    # a java.lang.Throwable occurring at the last line of this code block... 
# print "lots of stuff first" 
# print "lots 2" 
# handle_exc() 
# print "lots 3" 
# print "lots of stuff after" 

    try: 
     print "lots of stuff first" 
     print "lots 2" 
     handle_exc() 
     print "lots 3" 
     print "lots of stuff after" 
    # NB do not catch both (Python) BaseException and java.lang.Throwable... 
# except (BaseException, java.lang.Throwable), e: 
    # the above means that the line no. in handle_exc is not shown when a BaseException 
    # is thrown... 
    except java.lang.Throwable, t: 
     tb = sys.exc_info()[ 2 ] 
     sys.stderr.write("java.lang.Throwable thrown at: %s\n" % tb.tb_lineno) 
     raise t 

java.awt.EventQueue.invokeAndWait(Task()) 

Sau khi người này có thể nghĩ đến cách viết trang trí trước khi chạy (tự) và các phương pháp tương tự để bạn không phải ghi ra lần thử này. . cụ thể:

def throw_trap(function): 
    def wrapper(*args, **kvargs): 
    try: 
     return function(*args, **kvargs) 
    except java.lang.Throwable, t: 
     tb = sys.exc_info()[ 2 ] 
     while(tb): 
     sys.stderr.write("thrown at: %s\n" % tb.tb_lineno) 
     tb = tb.tb_next 
     raise t 
    return wrapper 



def handle_exc(): 
    java.lang.String(None) 
# a = 16/0 


class Task(java.lang.Runnable): 
    @throw_trap 
    def run(self): 
    print "lots of stuff first" 
    print "lots 2" 
    handle_exc() 
    print "lots 3" 
    print "lots of stuff after" 

java.awt.EventQueue.invokeAndWait(Task()) 
8

FWIW, tôi đã phát hiện ra rằng nếu bạn thêm nhập khẩu này để kịch bản Jython của bạn:

from java.lang import Exception 

và chỉ cần sử dụng thông thường handler Python Ngoại lệ:

except Exception, e: 

nó sẽ bắt cả ngoại lệ Python Java ngoại lệ

Các vấn đề liên quan