2011-01-05 16 views
32

मैं खिड़कियों पर लिख रहा हूँ अजगर 2.6.6 कोड है कि इस तरह दिखता है:मैं अजगर में कीबोर्ड इंटरप्ट को क्यों नहीं संभाल सकता?

try: 
    dostuff() 
except KeyboardInterrupt: 
    print "Interrupted!" 
except: 
    print "Some other exception?" 
finally: 
    print "cleaning up...." 
    print "done." 

dostuff() एक समारोह है कि हमेशा के लूप होता है, एक इनपुट स्ट्रीम से एक समय में एक लाइन पढ़ने और उस पर कार्य है। जब मैं ctrl-c दबाता हूं तो मैं इसे रोकने और साफ़ करने में सक्षम होना चाहता हूं।

इसके बजाय क्या हो रहा है यह है कि except KeyboardInterrupt: के तहत कोड बिल्कुल नहीं चल रहा है। केवल एक चीज प्रिंट हो जाती है कि "की सफाई ..." है, और फिर एक ट्रैस बैक छपा है कि इस तरह दिखता है:

Traceback (most recent call last): 
    File "filename.py", line 119, in <module> 
    print 'cleaning up...' 
KeyboardInterrupt 

तो, अपवाद हैंडलिंग कोड नहीं चल रहा है, और ट्रैस बैक का दावा है कि एक KeyboardInterrupt हुआ अंत में खंड के दौरान, जो समझ में नहीं आता है क्योंकि ctrl-c को मारना उस भाग को पहली जगह चलाने के कारण होता है! यहां तक ​​कि सामान्य except: खंड नहीं चल रहा है।

संपादित करें: टिप्पणियों के आधार पर, मैं sys.stdin.read साथ try: ब्लॉक की सामग्री को बदल दिया()। समस्या अभी भी वर्णन की गई है, जैसा कि finally: ब्लॉक की पहली पंक्ति के साथ चल रहा है और फिर उसी ट्रेसबैक को प्रिंट करना है।

संपादित करें # 2: यदि मैं पढ़ने के बाद बहुत कुछ जोड़ता हूं, हैंडलर काम करता है। तो, यह विफल रहता है:

try: 
    sys.stdin.read() 
except KeyboardInterrupt: 
    ... 

लेकिन यह काम करता है:

try: 
    sys.stdin.read() 
    print "Done reading." 
except KeyboardInterrupt: 
    ... 

यहाँ क्या मुद्रित है: "। पढ़ने हो गया"

Done reading. Interrupted! 
cleaning up... 
done. 

तो, किसी कारण से, लाइन मुद्रित है, भले ही अपवाद पिछली पंक्ति पर हुआ। यह वास्तव में एक समस्या नहीं है - जाहिर है, मुझे "कोशिश" ब्लॉक के अंदर कहीं भी अपवाद को संभालने में सक्षम होना चाहिए। हालांकि, प्रिंट सामान्य रूप से काम नहीं करता है - यह बाद में एक नई लाइन मुद्रित नहीं करता है जैसा कि यह माना जाता है! "इंटरप्टेड" एक ही पंक्ति पर मुद्रित है ... इससे पहले एक जगह के साथ, किसी कारण से ...? वैसे भी, उसके बाद कोड वह करता है जो इसे माना जाता है।

ऐसा लगता है कि यह अवरुद्ध सिस्टम कॉल के दौरान बाधा को संभालने में एक बग है।

+5

अपने dostuff() के लिए कोड दिखाएं, क्योंकि इस कोड को काम करना चाहिए (और यह करता है) – user225312

+0

यह पाइथन 2.5.1 के साथ अपेक्षित काम करता है। – khachik

+4

पायथन 2.7 के साथ पुन: उत्पन्न हुआ, 'sys.stdin.read()' – balpha

उत्तर

0

यहाँ क्या हो रहा है के बारे में एक अनुमान है: (? जो भी कारण ... बग Win32 सीमा के लिए)

  • दबाने Ctrl-C टूट जाता है "प्रिंट" बयान
  • दबाने Ctrl-C भी फेंकता पहला कीबोर्ड इंटरप्ट, dostuff()
  • अपवाद हैंडलर चलता है और "बाधित" प्रिंट करने का प्रयास करता है, लेकिन "प्रिंट" कथन टूट जाता है और एक और कीबोर्ड इंटरप्ट को फेंकता है।
  • अंत में खंड चलता है और "सफाई" .... प्रिंट करने का प्रयास करता है, लेकिन "प्रिंट" कथन टूट जाता है और अभी तक एक और कीबोर्ड इंटरप्ट को फेंकता है।
+0

क्या आप समस्या को पुन: उत्पन्न करने में सक्षम हैं? विंडोज़ मुझे लगता है? – user225312

+1

कोई अपवाद नहीं है कि अपवाद "प्रिंट" को तोड़ सकता है (या उस मामले के लिए कोई अन्य फ़ंक्शन)। इसके अलावा यह उपरोक्त अपवाद को संभालने के दौरान "एन-टाइम्स-स्टैक्ड" होगा, बीच में एक और अपवाद हुआ है। – delnan

18

असीमित अपवाद हैंडलिंग दुर्भाग्य से विश्वसनीय नहीं है (सिग्नल हैंडलर द्वारा उठाए गए अपवाद, सी एपीआई के माध्यम से संदर्भों के बाहर, आदि)।कोड में कुछ समन्वय होने के बारे में कोड में कुछ समन्वय होने पर आप एसिंक अपवाद को ठीक से संभालने की संभावनाओं को बढ़ा सकते हैं (कॉल स्टैक में उच्चतम संभव बहुत महत्वपूर्ण कार्यों को छोड़कर उचित लगता है)।

बुलाया गया फ़ंक्शन (dostuff) या स्टैक के नीचे फ़ंक्शंस के पास स्वयं को कीबोर्ड इंटरप्ट या बेस अपवाद के लिए पकड़ हो सकती है जिसे आपने खाता नहीं दिया/नहीं कर सका।

यह तुच्छ मामले अजगर 2.6.6 (64) इंटरैक्टिव + विंडोज 7 (64 बिट) के साथ ठीक काम किया:

>>> import time 
>>> def foo(): 
...  try: 
...    time.sleep(100) 
...  except KeyboardInterrupt: 
...    print "INTERRUPTED!" 
... 
>>> foo() 
INTERRUPTED! #after pressing ctrl+c 

संपादित करें:

आगे की जांच पड़ताल करने पर, मैंने कोशिश की है कि मैं क्या विश्वास करते हैं उदाहरण है कि दूसरों ने इस मुद्दे को पुन: उत्पन्न करने के लिए उपयोग किया है। मैं आलसी था इसलिए मैंने "आखिरकार"

>>> def foo(): 
...  try: 
...    sys.stdin.read() 
...  except KeyboardInterrupt: 
...    print "BLAH" 
... 
>>> foo() 

यह CTRL + C को मारने के तुरंत बाद लौटता है। दिलचस्प बात तब हुई जब मैंने तुरंत फिर से foo कॉल करने का प्रयास किया:

>>> foo() 

Traceback (most recent call last): 
    File "c:\Python26\lib\encodings\cp437.py", line 14, in decode 
    def decode(self,input,errors='strict'): 
KeyboardInterrupt 

अपवाद बिना सीटीआरएल + सी को मारने के तुरंत बाद उठाया गया था।

यह समझ में आता है - ऐसा प्रतीत होता है कि हम पाइथन में एसिंक्रोनस अपवादों को कैसे प्रबंधित करते हैं, इस बारे में बात कर रहे हैं। एसिंक अपवाद वास्तव में पॉप किया गया है और फिर वर्तमान निष्पादन संदर्भ में उठाए जाने से पहले यह कई बाइटकोड निर्देश ले सकता है। http://docs.python.org/c-api/init.html#PyThreadState_SetAsyncExc

तो यह कुछ हद तक बताता है कि क्यों KeyboardInterrupt में अंत में बयान के निष्पादन के संदर्भ में उठाया जाता है:

सी API देखें (यह व्यवहार है कि मैंने देखा है जब अतीत में यह के साथ खेल है) इस उदाहरण:

>>> def foo(): 
...  try: 
...    sys.stdin.read() 
...  except KeyboardInterrupt: 
...    print "interrupt" 
...  finally: 
...    print "FINALLY" 
... 
>>> foo() 
FINALLY 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 7, in foo 
KeyboardInterrupt 

कस्टम संकेत संचालकों दुभाषिया के मानक KeyboardInterrupt/CTRL + C हैंडलर है कि व्यवहार की इस तरह है, जिसके परिणामस्वरूप है के साथ मिश्रित की कुछ पागल मिश्रण हो सकता है। उदाहरण के लिए, पढ़ा() कॉल सिग्नल और बेल्स देखता है, लेकिन यह इसके हैंडलर को अपनाने के बाद सिग्नल को फिर से उठाता है। मैं दुभाषिया कोडबेस का निरीक्षण किए बिना निश्चित रूप से नहीं जानता।

यही कारण है कि मैं आम तौर पर async अपवादों में से इस्तेमाल करने से संकोच ....

संपादित 2

मुझे लगता है कि वहाँ एक बग रिपोर्ट के लिए एक अच्छा मामला है।

फिर अधिक सिद्धांतों ... (बस पढ़ते कोड के आधार पर) फ़ाइल वस्तु स्रोत देखें: http://svn.python.org/view/python/branches/release26-maint/Objects/fileobject.c?revision=81277&view=markup

file_read Py_UniversalNewlineFread कॉल()। fread errno = EINTR के साथ एक त्रुटि के साथ वापस आ सकता है (यह अपने स्वयं के सिग्नल हैंडलिंग करता है)। इस मामले में Py_UniversalNewlineFread() बेल्स लेकिन PyErr_CheckSignals() के साथ कोई सिग्नल चेकिंग नहीं करता है ताकि हैंडलर को सिंक्रनाइज़ेशन कहा जा सके। file_read फ़ाइल त्रुटि को साफ़ करता है लेकिन यह PyErr_CheckSignals() को भी कॉल नहीं करता है।

इसके उपयोग के उदाहरणों के लिए getline() और getline_via_fgets() देखें। पैटर्न को इसी समस्या के लिए इस बग रिपोर्ट में दस्तावेज किया गया है: (http://bugs.python.org/issue1195)।तो ऐसा लगता है कि सिग्नल दुभाषिया द्वारा अनिश्चित समय पर संभाला जाता है।

मुझे लगता है कि डाइविंग में कोई गहराई से कोई गहराई नहीं है क्योंकि यह अभी भी स्पष्ट नहीं है कि sys.stdin.read() उदाहरण आपके "dostuff()" फ़ंक्शन का उचित एनालॉग है या नहीं।

+0

लेकिन अन्य (मुझे सहित - विंडोज 7 32 बिट पाइथन 3 के साथ) ने इसे 'डोस्टफ' प्रतिस्थापन के साथ पुन: उत्पन्न किया है जो कीबोर्ड इंटरप्ट को पकड़ नहीं लेता है। – delnan

+0

@ डेलन - उत्तर विस्तारित। उम्मीद है कि यह कुछ सिद्धांतों को तैयार करने में मदद करता है! :) –

+4

मैं इसे एक अचूक बग के रूप में एसिंक्रोनस अपवादों में "न्युअंस" नहीं कहूंगा। यदि अपवाद तकनीकी रूप से होने के बाद थोड़ा सा उठाया जाता है, तो यह ठीक है ... लेकिन अगर अपवाद उठाया गया है तो कोशिश करें कि अपवाद टूट गया है, यह एक और कहानी है। कई अच्छी तरह से प्रलेखित व्यवहार स्पष्ट रूप से यहां टूटे हुए हैं, सबसे महत्वपूर्ण बात यह है कि "आखिरकार" ब्लॉक "गारंटीकृत" क्लीन-अप कोड नहीं चलाता है; और यह भी कि कोई अपवाद हैंडलर तब भी चलाया जाता है जब कम से कम एक अपवाद एक "कोशिश" ब्लॉक के भीतर अनजाने में हुआ। – Josh

0

यह मेरे लिए काम करता (वहाँ खेलने में कई कीड़े हो सकता है):

import sys 

if __name__ == "__main__": 
    try: 
     sys.stdin.read() 
     print "Here" 
    except KeyboardInterrupt: 
     print "Worked" 
    except: 
     print "Something else" 
    finally: 
     print "Finally" 

अपने dostuff() फ़ंक्शन के बाहर एक लाइन डालने का प्रयास करें या समारोह के बाहर पाश हालत चलते हैं। उदाहरण के लिए:

try: 
    while True: 
     dostuff() 
except KeyboardInterrupt: 
    print "Interrupted!" 
except: 
    print "Some other exception?" 
finally: 
    print "cleaning up...." 
    print "done." 
1

sys.stdin.read() एक सिस्टम कॉल और इतने व्यवहार प्रत्येक प्रणाली के लिए अलग अलग होने जा रहा है है। विंडोज 7 के लिए मुझे लगता है कि क्या हो रहा है यह है कि इनपुट buffered किया जा रहा है और इसलिए आप sys.stdin.read() सबकुछ Ctrl-C पर वापस कर रहे हैं और जैसे ही आप sys.stdin को फिर से एक्सेस करते हैं, यह "Ctrl- सी"।

निम्नलिखित का प्रयास करें,

def foo(): 
    try: 
     print sys.stdin.read() 
     print sys.stdin.closed 
    except KeyboardInterrupt: 
     print "Interrupted!" 

यह है कि वहाँ stdin कि चल रहा की बफरिंग पता चलता है

def foo(): 
    try: 
     x=0 
     while 1: 
      x += 1 
     print x 
    except KeyboardInterrupt: 
     print "Interrupted!" 

वहाँ प्रकट नहीं होता कीबोर्ड इनपुट पहचान करने के लिए stdin के लिए एक और कॉल खड़ी कर रहा है एक समस्या होने के लिए।

dostuff() stdin से पढ़ रहा है?

+0

मुझे लगता है कि आप कुछ पर हैं, सिवाय इसके कि अगर आप किसी अन्य कमांड के साथ sys.stdin.closed को प्रतिस्थापित करते हैं, जिसमें प्रिंट या नींद भी शामिल है, जो इसे काम करने का कारण बनती है। मुझे नहीं लगता कि दूसरी बार stdin तक पहुंचना जरूरी है ... मुझे लगता है कि शायद ctrl-c को मारने से सिस्टम कॉल वापस आती है और फिर भी सॉफ़्टवेयर में बाधा भेजती है, लेकिन पाइथन इंटरप्ट को तब तक संभाल नहीं लेता है जब तक कि कोड की अगली पंक्ति ... तब तक यह पहले से ही कोशिश ब्लॉक से बाहर है! – Josh

+0

ठीक है, लेकिन मुझे यकीन नहीं है कि आप अपने 'dostuff()' में क्या कर रहे हैं जो ऐसा नहीं होने का कारण भी होगा। – milkypostman

1

समान समस्या है और यह मेरा समाधान नहीं है:

try: 
    some_blocking_io_here() # CTRL-C to interrupt 
except: 
    try: 
     print() # any i/o will get the second KeyboardInterrupt here? 
    except: 
     real_handler_here() 
0
def foo(): 
    try: 
     x=0 
     while 1: 
      x+=1 
      print (x) 
    except KeyboardInterrupt: 
     print ("interrupted!!") 
foo() 

यह ठीक काम करता है।

संबंधित मुद्दे