2010-11-17 20 views

Trả lời

122

Có, bạn có thể cài đặt trình xử lý ngắt bằng cách sử dụng signal module.

import signal 
import sys 
import time 

def signal_handler(signal, frame): 
    print 'You pressed Ctrl+C!' 
    sys.exit(0) 

signal.signal(signal.SIGINT, signal_handler) 
print 'Press Ctrl+C' 
while True: 
    time.sleep(1) 
+8

Lưu ý rằng có một số vấn đề nền tảng cụ thể với mô-đun tín hiệu - không ảnh hưởng đến áp phích này, nhưng "Trên Windows, tín hiệu() chỉ có thể được gọi với SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV hoặc SIGTERM. Một ValueError sẽ được nâng lên trong bất kỳ trường hợp nào khác. " – bgporter

+6

Hoạt động tốt với các chủ đề. Tôi hy vọng bạn không bao giờ làm 'trong khi True: continue', mặc dù. (Trong phong cách đó, 'trong khi True: pass' sẽ là neater, anyway.) Điều đó sẽ rất lãng phí; thử một cái gì đó như 'trong khi True: time.sleep (60 * 60 * 24)' (ngủ cho một ngày tại một thời điểm là một con số hoàn toàn tùy ý). –

+1

Nếu bạn đang sử dụng đề xuất của Chris Morgan về việc sử dụng 'time' (như bạn nên), đừng quên' thời gian nhập' :) – Seaux

4

Bạn có thể ngăn in dấu vết ngăn xếp cho KeyboardInterrupt, không có try: ... except KeyboardInterrupt: pass (giải pháp rõ ràng và tốt nhất "tốt nhất" nhưng bạn đã biết và yêu cầu) bằng cách thay thế sys.excepthook. Một cái gì đó như

def custom_excepthook(type, value, traceback): 
    if type is KeyboardInterrupt: 
     return # do nothing 
    else: 
     sys.__excepthook__(type, value, traceback) 
+0

tôi muốn thoát sạch không dấu vết nếu người dùng nhấn ctrl-c – Alex

+0

bị bắt ==> bị bắt –

+7

Điều này hoàn toàn không đúng. Ngoại lệ KeyboardInterrupt được tạo ra trong một trình xử lý ngắt. Trình xử lý mặc định cho SIGINT tăng KeyboardInterrupt vì vậy nếu bạn không muốn hành vi đó, tất cả những gì bạn phải làm là cung cấp một trình xử lý tín hiệu khác cho SIGINT. Bạn đang đúng trong trường hợp ngoại lệ đó chỉ có thể được xử lý trong một thử/ngoại trừ trong trường hợp này, bạn có thể giữ ngoại lệ từ bao giờ được nêu ra ở nơi đầu tiên. – Matt

25

Nếu tất cả các bạn muốn là để không hiển thị traceback, làm cho mã của bạn như thế này:

## all your app logic here 
def main(): 
    ## whatever your app does. 


if __name__ == "__main__": 
    try: 
     main() 
    except KeyboardInterrupt: 
     # do nothing here 
     pass 

(Vâng, tôi biết rằng điều này không trực tiếp trả lời các câu hỏi, nhưng nó không phải là thực sự rõ ràng lý do tại sao cần một khối try/except có thể bị phản đối - có thể điều này khiến nó ít gây phiền toái cho OP)

+2

Vì lý do nào đó, điều này không phải lúc nào cũng hiệu quả đối với tôi. 'signal.signal (signal.SIGINT, lambda s, f: sys.exit (0))' luôn xảy ra. –

+0

Điều này không phải lúc nào cũng hoạt động với những thứ như pygtk sử dụng chủ đề. Đôi khi^C sẽ chỉ giết luồng hiện tại thay vì toàn bộ quá trình, do đó ngoại lệ sẽ chỉ truyền qua chuỗi đó. –

+0

Có một câu hỏi SO cụ thể về Ctrl + C với pygtk: http://stackoverflow.com/questions/16410852/keyboard-interrupt-with-with-python-gtk – bgporter

23

Một cách khác để thiết lập trình xử lý tín hiệu của bạn là sử dụng trình quản lý ngữ cảnh để loại trừ ngoại lệ và bỏ qua nó:

>>> class CleanExit(object): 
...  def __enter__(self): 
...    return self 
...  def __exit__(self, exc_type, exc_value, exc_tb): 
...    if exc_type is KeyboardInterrupt: 
...      return True 
...    return exc_type is None 
... 
>>> with CleanExit(): 
...  input() #just to test it 
... 
>>> 

Thao tác này sẽ xóa khối try - except trong khi vẫn giữ một số đề cập rõ ràng về những gì đang diễn ra.

Điều này cũng cho phép bạn bỏ qua ngắt chỉ trong một số phần mã của bạn mà không phải đặt lại và đặt lại trình xử lý tín hiệu mọi lúc.

+1

tốt đẹp, giải pháp này có vẻ trực tiếp hơn một chút trong việc thể hiện mục đích hơn là đối phó với các tín hiệu. – Seaux

4

Tôi biết đây là một câu hỏi cũ nhưng tôi đã đến đây trước và sau đó phát hiện ra mô-đun atexit. Tôi không biết về hồ sơ theo dõi đa nền tảng của nó hoặc một danh sách đầy đủ các cảnh báo nào được nêu ra, nhưng cho đến nay nó là chính xác những gì tôi đang tìm kiếm trong cố gắng để xử lý sau KeyboardInterrupt dọn dẹp trên Linux. Chỉ muốn ném theo một cách khác để tiếp cận vấn đề.

Tôi muốn làm sạch sau khi xuất cảnh trong bối cảnh hoạt động của Vải, do đó, bao gói mọi thứ trong try/except cũng không phải là một tùy chọn cho tôi. Tôi cảm thấy như atexit có thể phù hợp trong tình huống như vậy, nơi mã của bạn không ở mức cao nhất của luồng điều khiển.

atexit là rất có khả năng và có thể đọc được ra khỏi hộp, ví dụ:

import atexit 

def goodbye(): 
    print "You are now leaving the Python sector." 

atexit.register(goodbye) 

Bạn cũng có thể sử dụng nó như một trang trí (như 2,6; ví dụ này là từ các tài liệu):

import atexit 

@atexit.register 
def goodbye(): 
    print "You are now leaving the Python sector." 

Nếu bạn muốn chỉ định riêng cho KeyboardInterrupt, câu trả lời của người khác cho câu hỏi này có lẽ tốt hơn. Tuy nhiên, lưu ý rằng mô-đun atexit chỉ là ~ 70 dòng mã và sẽ không khó để tạo ra một phiên bản tương tự xử lý các ngoại lệ khác nhau, ví dụ như truyền ngoại lệ làm đối số cho hàm gọi lại.(Giới hạn của atexit mà sẽ đảm bảo một phiên bản sửa đổi: hiện tại tôi không thể quan niệm một cách cho các chức năng gọi lại-exit để biết về các trường hợp ngoại lệ; .. -raises ngoại lệ mà Nhưng bạn có thể làm điều này khác nhau)

Để biết thêm thông xem:

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