कैसे एक कीस्ट्रोक के साथ थोड़ी देर लूप को मारने के लिए?


86

मैं थोड़ी देर के लूप का उपयोग करते हुए सीरियल डेटा और सीएसवी फ़ाइल को लिख रहा हूं। मैं चाहता हूं कि उपयोगकर्ता एक बार लूप को मारने में सक्षम हो जाएं जब उन्हें लगता है कि उन्होंने पर्याप्त डेटा एकत्र किया है।

while True:
    #do a bunch of serial stuff

    #if the user presses the 'esc' or 'return' key:
        break

मैंने opencv का उपयोग करके ऐसा कुछ किया है, लेकिन यह इस एप्लिकेशन में काम नहीं करता है (और मैं वास्तव में इस फ़ंक्शन के लिए वैसे भी opencv आयात नहीं करना चाहता) ...

        # Listen for ESC or ENTER key
        c = cv.WaitKey(7) % 0x100
        if c == 27 or c == 10:
            break

इसलिए। मैं उपयोगकर्ता को लूप से बाहर कैसे जाने दे सकता हूं?

इसके अलावा, मैं कीबोर्ड इंटरप्ट का उपयोग नहीं करना चाहता हूं, क्योंकि लूप समाप्त होने के बाद स्क्रिप्ट को जारी रखने की आवश्यकता होती है।

जवाबों:


143

सबसे आसान तरीका यह है कि इसे सामान्य Ctrl-C(SIGINT) से बाधित करें ।

try:
    while True:
        do_something()
except KeyboardInterrupt:
    pass

चूंकि उठाए जाने का Ctrl-Cकारण बनता KeyboardInterruptहै, बस इसे लूप के बाहर पकड़ें और इसे अनदेखा करें।


2
@ क्रिस: आप इसे एक कोशिश क्यों नहीं देते। (और फिर टिप्पणी)
साइलेंटगॉस्ट

यह क्रैश (मुझे त्रुटि का पता लगाता है) ^Cजारी करते समय जारी किया जाता है do_something()। आप इससे कैसे बच सकते हैं?
Atcold

मेरा do_something()USB से कुछ मूल्यों को पढ़ता है, इसलिए, अगर ^Cमैं अंदर do_something()हूं तो जारी किया जाता है जब मुझे बुरा संचार त्रुटि मिलती है। इसके बजाय, अगर मैं अंदर हूँ while, बाहर do_something(), सब चिकना है। इसलिए, मैं सोच रहा था कि इस स्थिति को कैसे संभालना है। मुझे यकीन नहीं है कि मैंने खुद को पर्याप्त स्पष्ट कर दिया है।
Atcold

@Atcold तो आपके पास एक संकलित विस्तार मॉड्यूल है जो आप उपयोग कर रहे हैं। यह किस तरह का मॉड्यूल है? क्या यह एक सामान्य सी लाइब्रेरी लपेटी जा रही है?
कीथ

मेरे पास एक कॉल टू pyVISAऔर एक कॉल है matplotlib, ताकि मैं अपने माप का लाइव विज़ुअलाइज़ेशन कर सकूं। और मुझे कभी-कभी फनी त्रुटियाँ मिलती हैं। मुझे लगता है कि मुझे एक अलग प्रश्न खोलना चाहिए और आपके उत्तर को प्रदूषित करना बंद कर देना चाहिए ...
Atcold

34

एक ऐसा समाधान है जिसके लिए किसी गैर-मानक मॉड्यूल की आवश्यकता नहीं है और यह 100% परिवहनीय है

import thread

def input_thread(a_list):
    raw_input()
    a_list.append(True)

def do_stuff():
    a_list = []
    thread.start_new_thread(input_thread, (a_list,))
    while not a_list:
        stuff()

4
पायथन 3+ का उपयोग करने वालों के लिए बस एक नोट: raw_input () का नाम बदलकर इनपुट () कर दिया गया है, और थ्रेड मॉड्यूल अब _thread है।
विस्ची

अजगर 3 डॉक्स के अनुसार, अजगर 3 में काम नहीं किया: "थ्रेड इंटरट्रेट्स के साथ अजीब तरीके से बातचीत करते हैं: कीबोर्डइंटरप्ट अपवाद एक मनमाना धागा द्वारा प्राप्त होगा। (जब सिग्नल मॉड्यूल उपलब्ध होता है, तो व्यवधान हमेशा मुख्य धागे पर जाता है।")
ताहिद

@Thhid लेकिन इसमें इंटरप्ट का उपयोग नहीं किया गया है। यह स्टड से पढ़ने का उपयोग करता है।
आर्यटन

@Artyer अगर मैं गलत नहीं हूँ तो सभी कीस्ट्रोक इंटरप्ट बढ़ाते हैं, क्योंकि वे एक हार्डवेयर द्वारा उठाए जाते हैं। क्या इस कोड ने आपके लिए काम किया, और यदि आपने कोई विशिष्ट परिवर्तन किया है?
तौहीद

2
@ बस thread-> _threadऔर raw_input-> input। आपको लाइन खिलाने के लिए एंटर दबाना होगा। यदि आप किसी भी कुंजी पर करना चाहते हैं, तो getch का उपयोग करें ।
११:

14

निम्नलिखित कोड मेरे लिए काम करता है। इसके लिए ओपनसीवी (आयात cv2) की आवश्यकता है।

कोड एक अनंत लूप से बना होता है जो लगातार एक कुंजी दबाए रहता है। इस स्थिति में, जब 'q' कुंजी दबाया जाता है, तो प्रोग्राम समाप्त हो जाता है। अन्य क्रियाओं को दबाया जा सकता है (इस उदाहरण में 'b' या 'k') जैसे अलग-अलग कार्यों को करने के लिए जैसे कि एक वैरिएबल मान को बदलना या किसी फ़ंक्शन को निष्पादित करना।

import cv2

while True:
    k = cv2.waitKey(1) & 0xFF
    # press 'q' to exit
    if k == ord('q'):
        break
    elif k == ord('b'):
        # change a variable / do something ...
    elif k == ord('k'):
        # change a variable / do something ...

5
अच्छा है, लेकिन cv2 बहुत भारी है, जब तक कि आप पहले से ही इसे किसी और चीज के लिए उपयोग नहीं कर रहे हैं।
बजे

1
क्यों और 255 के साथ
Talespin_Kit

@Talespin_Kit & 0xff ”वेरिएबल को मास्क करता है, इसलिए यह पिछले 8 बिट्स में केवल वैल्यू छोड़ता है, और बाकी सभी बिट्स को अनदेखा करता है। मूल रूप से यह सुनिश्चित करता है कि परिणाम 0-255 के भीतर होगा। नोट मैं कभी भी opencv में ऐसा नहीं करता और चीजें ठीक काम करती हैं।
इरिक

6

Python 3.7 के लिए, मैंने user297171 द्वारा बहुत अच्छे उत्तर की प्रतिलिपि बनाई और बदल दी, इसलिए यह Python 3.7 में सभी परिदृश्यों में काम करता है जिसका मैंने परीक्षण किया था।

import threading as th

keep_going = True
def key_capture_thread():
    global keep_going
    input()
    keep_going = False

def do_stuff():
    th.Thread(target=key_capture_thread, args=(), name='key_capture_thread', daemon=True).start()
    while keep_going:
        print('still going...')

do_stuff()

मुझे नहीं पता कि मैं कुछ गलत कर रहा हूँ या क्या, लेकिन मैं यह नहीं जान सकता कि इस पाश को कैसे रोका जाए? आप उसे कैसे करते हैं?
मिहकेल

@ मिहकेल आपको <Enter> कुंजी दबाना है। इससे लूप बाहर निकल जाएगा।
रेइजिन्स

यह सभ्य है, लेकिन प्रवेश के अलावा अन्य कुंजियों का सामान्यीकरण नहीं करता है।
जॉन फोर्ब्स

python2.7 पर मेरे लिए काम नहीं करता है, लेकिन python3 पर काम करता है
crazjo

मल्टीथ्रेडिंग करना मेरे दिमाग में भी है, लेकिन मुझे @Keith का जवाब काफी पसंद है। सरल और पर्याप्त स्पष्ट।
आदी

4

pyHook मदद कर सकता है। http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=PyHook_Tutorial#tocpyHook%5FTutorial4

कीबोर्ड हुक देखें; यह अधिक सामान्यीकृत है - यदि आप विशिष्ट कीबोर्ड इंटरैक्शन चाहते हैं और केवल कीबोर्डइंटरप्ट का उपयोग नहीं कर रहे हैं।

इसके अलावा, सामान्य तौर पर (आपके उपयोग के आधार पर) मुझे लगता है कि आपकी स्क्रिप्ट को मारने के लिए अभी भी Ctrl-C विकल्प उपलब्ध है जो समझ में आता है।

पिछले प्रश्न को भी देखें: अजगर में पता लगाएं कि कौन सी कुंजी दबाया गया है


1

हमेशा है sys.exit()

पायथन की मुख्य लाइब्रेरी में सिस्टम लाइब्रेरी का एक एक्ज़िट फंक्शन है जो प्रोटोटाइप करते समय बहुत काम आता है। कोड की तर्ज पर होगा:

import sys

while True:
    selection = raw_input("U: Create User\nQ: Quit")
    if selection is "Q" or selection is "q":
        print("Quitting")
        sys.exit()
    if selection is "U" or selection is "u":
        print("User")
        #do_something()

अजगर 3 raw_inputमें प्रतिस्थापित हैinput
तल्हा अनवर

1

मैंने एक विशिष्ट कुंजी के साथ स्क्रिप्ट को समाप्त करने के लिए रेज़िनज़ से उत्तर को संशोधित किया, इस मामले में एस्केप कुंजी

import threading as th
import time
import keyboard

keep_going = True
def key_capture_thread():
    global keep_going
    a = keyboard.read_key()
    if a== "esc":
        keep_going = False


def do_stuff():
    th.Thread(target=key_capture_thread, args=(), name='key_capture_thread', daemon=True).start()
    i=0
    while keep_going:
        print('still going...')
        time.sleep(1)
        i=i+1
        print (i)
    print ("Schleife beendet")


do_stuff()

नमस्कार! हालांकि यह कोड प्रश्न को हल कर सकता है, जिसमें यह भी बताया गया है कि यह समस्या कैसे और क्यों हल करती है, इससे वास्तव में आपके पोस्ट की गुणवत्ता को बेहतर बनाने में मदद मिलेगी, और शायद अधिक वोट भी मिलेंगे। याद रखें कि आप भविष्य में पाठकों के लिए सवाल का जवाब दे रहे हैं, न कि केवल उस व्यक्ति से जो अब पूछ रहा है। कृपया स्पष्टीकरण जोड़ने के लिए अपने उत्तर को संपादित करें और संकेत दें कि क्या सीमाएँ और मान्यताएँ लागू होती हैं।
ब्रायन

1

खरगोश छेद नीचे इस धागे का पालन करने से, मैं इस पर आया था, Win10 और Ubuntu 20.04 पर काम करता है। मैं स्क्रिप्ट को मारने और विशिष्ट कुंजी का उपयोग करने से अधिक चाहता था, और इसे एमएस और लिनक्स दोनों में काम करना था।

import _thread
import time
import sys
import os

class _Getch:
    """Gets a single character from standard input.  Does not echo to the screen."""
    def __init__(self):
        try:
            self.impl = _GetchWindows()
        except ImportError:
            self.impl = _GetchUnix()

    def __call__(self): return self.impl()

class _GetchUnix:
    def __init__(self):
        import tty, sys

    def __call__(self):
        import sys, tty, termios
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(sys.stdin.fileno())
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

class _GetchWindows:
    def __init__(self):
        import msvcrt

    def __call__(self):
        import msvcrt
        msvcrt_char = msvcrt.getch()
        return msvcrt_char.decode("utf-8")

def input_thread(key_press_list):
    char = 'x'
    while char != 'q': #dont keep doing this after trying to quit, or 'stty sane' wont work
        time.sleep(0.05)
        getch = _Getch()
        char = getch.impl()
        pprint("getch: "+ str(char))
        key_press_list.append(char)

def quitScript():
    pprint("QUITTING...")
    time.sleep(0.2) #wait for the thread to die
    os.system('stty sane')
    sys.exit()

def pprint(string_to_print): #terminal is in raw mode so we need to append \r\n
    print(string_to_print, end="\r\n")

def main():
    key_press_list = []
    _thread.start_new_thread(input_thread, (key_press_list,))
    while True:
        #do your things here
        pprint("tick")
        time.sleep(0.5)

        if key_press_list == ['q']:
            key_press_list.clear()
            quitScript()

        elif key_press_list == ['j']:
            key_press_list.clear()
            pprint("knock knock..")

        elif key_press_list:
            key_press_list.clear()

main()

0

यह सहायक हो सकता है स्थापित करें - पाइप स्थापित करें

from pynput.keyboard import Key, Listener
def on_release(key):
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
while True:
    with Listener(
            on_release=on_release) as listener:
        listener.join()
    break 

0

यह वह उपाय है जो मुझे थ्रेड्स और मानक पुस्तकालयों के साथ मिला है।

लूप तब तक
चलता रहता है जब तक कि एक कुंजी को दबाया नहीं जाता है । कुंजी को एक ही वर्ण स्ट्रिंग के रूप में दबाया जाता है

। पायथन 2.7 और 3 में काम करता है।

import thread
import sys

def getch():
    import termios
    import sys, tty
    def _getch():
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try:
            tty.setraw(fd)
            ch = sys.stdin.read(1)
        finally:
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch
    return _getch()

def input_thread(char):
    char.append(getch())

def do_stuff():
    char = []
    thread.start_new_thread(input_thread, (char,))
    i = 0
    while not char :
        i += 1

    print "i = " + str(i) + " char : " + str(char[0])

do_stuff()

-1
import keyboard

while True:
    print('please say yes')
    if keyboard.is_pressed('y'):
         break
print('i got u :) ')
print('i was trying to write you are a idiot ')
print('  :( ')

प्रवेश के लिए 'ENTER' का उपयोग करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.