키 입력으로 while 루프를 종료하는 방법은 무엇입니까?


88

직렬 데이터를 읽고 while 루프를 사용하여 csv 파일에 쓰고 있습니다. 사용자가 충분한 데이터를 수집했다고 느끼면 while 루프를 종료 할 수 있기를 바랍니다.

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

그래서. 사용자가 루프를 벗어나게하려면 어떻게해야합니까?

또한 while 루프가 종료 된 후에도 스크립트가 계속 실행되어야하므로 키보드 인터럽트를 사용하고 싶지 않습니다.

답변:


144

가장 쉬운 방법은 일반적인 Ctrl-C(SIGINT)로 중단하는 것입니다 .

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

이후 Ctrl-C원인이 KeyboardInterrupt제기 될 단지 루프 밖에서 그것을 잡을 그것을 무시한다.


2
@Chris : 시도해 보지 그래요. (후 주석)
SilentGhost

이 충돌은 (I 오류 추적 등을 얻을)되어 ^C있는 동안 발행됩니다 do_something(). 이것을 어떻게 피할 수 있습니까?
Atcold

do_something()USB에서 일부 값을 읽으므로 ^C내부에있는 동안 발행 되면 do_something()불쾌한 통신 오류가 발생합니다. 대신에 while, 외부 에 있으면 do_something()모든 것이 부드럽습니다. 그래서이 상황을 어떻게 처리해야할지 궁금했습니다. 내 자신을 충분히 명확하게했는지 모르겠습니다.
Atcold

@Atcold 따라서 사용중인 컴파일 된 확장 모듈이 있습니다. 어떤 종류의 모듈입니까? 랩핑되는 공통 C 라이브러리입니까?
키스

에 대한 전화 pyVISA와에 대한 전화가 matplotlib있으므로 측정을 실시간으로 시각화 할 수 있습니다. 그리고 가끔 펑키 한 오류가 발생합니다. 나는 ... 별도의 질문을 열고 답변을 오염 중지해야한다고 생각
Atcold

36

비표준 모듈이 필요하지 않고 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()

5
Python 3 이상을 사용하는 사람들을위한 참고 사항 : raw_input ()은 input ()으로 이름이 바뀌었고 스레드 모듈은 이제 _thread입니다.
Wieschie

파이썬 3 문서에 따르면 파이썬 3에서는 작동하지 않았습니다. "스레드는 인터럽트와 이상하게 상호 작용합니다. KeyboardInterrupt 예외는 임의의 스레드에 의해 수신됩니다. (신호 모듈을 사용할 수있을 때 인터럽트는 항상 주 스레드로 이동합니다.)"
Towhid

@Towhid 그러나 이것은 인터럽트를 사용하지 않습니다. stdin에서 읽기를 사용합니다.
Artyer

@Artyer 내가 착각하지 않으면 모든 키 입력은 하드웨어에 의해 발생하기 때문에 인터럽트를 발생시킵니다. 이 코드가 도움이 되었습니까? 그렇다면 특정 변경 사항을 적용 했습니까?
Towhid

2
@Towhid just- thread> _threadraw_input-> input. 줄을 입력하려면 Enter 키를 눌러야합니다. 키에 대해 수행하려면 getch를 사용하십시오 .
Artyer

14

다음 코드가 나를 위해 작동합니다. openCV (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는 이미 다른 용도로 사용하지 않는 한 너무 무겁습니다.
ogurets

1
왜 255
Talespin_Kit

@Talespin_Kit & 0xff”는 변수를 마스킹하여 마지막 8 비트의 값만 남기고 나머지 비트는 모두 무시합니다. 기본적으로 결과가 0-255 이내인지 확인합니다. 참고 나는 opencv에서 이것을하지 않으며 모든 것이 잘 작동합니다.
eric

7

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

내가 뭘 잘못하고 있는지 알 수 없지만이 루프를 중지하는 방법을 알 수 없습니까? 어떻게 하죠?
Mihkel

@Mihkel <Enter> 키를 눌러야합니다. 이렇게하면 루프가 종료됩니다.
rayzinnz

이것은 괜찮지 만 Enter 이외의 키로 일반화되지는 않습니다.
John Forbes

python2.7에 나를 위해하지 작업을 수행하지만, python3에서 작동
crazjo

멀티 스레딩을하는 것도 내 마음에 있지만 위의 @Keith의 대답을 아주 좋아합니다. 간단하고 명확합니다.
중독 됨

4

pyHook이 도움이 될 수 있습니다. http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=PyHook_Tutorial#tocpyHook%5FTutorial4

키보드 후크를 참조하십시오. 이것은보다 일반화되어 있습니다. KeyboardInterrupt를 사용하는 것이 아니라 특정 키보드 상호 작용을 원하는 경우입니다.

또한 일반적으로 (사용에 따라) Ctrl-C 옵션을 사용하여 스크립트를 종료하는 것이 합리적이라고 생각합니다.

이전 질문도 참조하십시오 : 눌린 키를 파이썬에서 감지 하십시오.


1

항상 sys.exit()있습니다.

Python 핵심 라이브러리의 시스템 라이브러리에는 프로토 타이핑시 매우 편리한 종료 기능이 있습니다. 코드는 다음과 같습니다.

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
Talha 안와르

1

특정 키 (이 경우 이스케이프 키)로 스크립트를 끝내도록 rayzinnz의 답변을 수정했습니다.

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

여보세요! 이 코드가 문제를 해결할 수 있지만 문제를 해결하는 방법과 이유에 대한 설명포함 하여 게시물의 품질을 향상시키는 데 실제로 도움이되며 더 많은 찬성 투표가 발생할 수 있습니다. 지금 질문하는 사람뿐만 아니라 미래에 독자를 위해 질문에 답하고 있다는 것을 기억하십시오. 제발 편집 설명을 추가하고 제한 및 가정이 적용 무엇의 표시를 제공하는 답변을.
Brian

1

이 스레드를 따라 토끼 구멍을 따라 가면서 Win10 및 Ubuntu 20.04에서 작동합니다. 스크립트를 죽이고 특정 키를 사용하는 것 이상을 원했고 MS와 Linux에서 모두 작동해야했습니다 ..

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

이것은 도움이 될 수 있습니다 설치 pynput-pip install pynput

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

이것은 스레드 및 표준 라이브러리에서 찾은 솔루션입니다

루프는 하나의 키를 누를 때까지 계속 진행
됩니다. 단일 문자열로 누른 키를 반환합니다

. Python 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'사용

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.