Bir tuş vuruşu ile bir while döngüsü nasıl kapatılır?


88

Seri verileri okuyorum ve while döngüsü kullanarak bir csv dosyasına yazıyorum. Kullanıcının yeterli veri topladığını hissettiğinde while döngüsünü sonlandırabilmesini istiyorum.

while True:
    #do a bunch of serial stuff

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

Opencv kullanarak böyle bir şey yaptım, ancak bu uygulamada çalışıyor gibi görünmüyor (ve yine de opencv'yi yalnızca bu işlev için içe aktarmak istemiyorum) ...

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

Yani. Kullanıcının döngüden çıkmasına nasıl izin verebilirim?

Ayrıca, klavye kesmesini kullanmak istemiyorum çünkü komut dosyasının while döngüsü sonlandırıldıktan sonra çalışmaya devam etmesi gerekiyor.

Yanıtlar:


144

En kolay yol, onu olağan Ctrl-C(SIGINT) ile kesmektir.

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

Yana Ctrl-Cnedenleri KeyboardInterruptyetiştirilmek üzere, sadece döngünün dışına yakalamak ve bunu görmezden.


2
@Chris: Neden denemiyorsun? (ve sonra yorum yapın)
SilentGhost

Bu çökmeler (geriye dönük hata takibi alıyorum) içerideyken ^Cverilir do_something(). Bundan nasıl kaçınabilirsin?
Atcold

Benim do_something()ise, bu nedenle, USB'den bazı değerleri okur ^Ciçimde olduğum sürece verilir do_something()ben kötü iletişim hataları olsun. Bunun yerine, içindeysem while, dışındaysam do_something(), her şey pürüzsüz. Bu yüzden bu durumla nasıl başa çıkacağımı merak ediyordum. Kendimi yeterince açıkladığımdan emin değilim.
Atcold

@Atcold Kullanmakta olduğunuz derlenmiş bir uzantı modülünüz var. Bu ne tür bir modül? Sarılmış ortak bir C kütüphanesi mi?
Keith

Ölçümlerimi canlı olarak görselleştirebilmem için bir telefon var pyVISAve bir telefon matplotlibvar. Ve bazen garip hatalar alıyorum. Sanırım ayrı bir soru açıp cevabınızı kirletmeyi bırakmalıyım ...
Atcold

36

Standart dışı modüller gerektirmeyen ve% 100 taşınabilir bir çözüm var

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+ kullananlar için sadece bir not: raw_input (), input () olarak yeniden adlandırıldı ve iş parçacığı modülü artık _thread oldu.
Wieschie

Python 3 belgelerine göre, python 3'te çalışmadı: "İplikler kesintilerle garip bir şekilde etkileşime giriyor: KeyboardInterrupt istisnası, rastgele bir iş parçacığı tarafından alınacak. (Sinyal modülü mevcut olduğunda, kesmeler her zaman ana iş parçacığına gider.)"
Towhid

@Towhid Ancak bu kesintileri kullanmaz. Stdin'den okuma kullanır.
Artyer

@Artyer Yanılmıyorsam tüm tuş vuruşları, bir donanım tarafından yükseltildikleri için kesintileri artırıyor. bu kod sizin için işe yaradı mı ve eğer öyleyse herhangi bir özel değişiklik yaptınız mı?
Towhid

2
@Towhid sadece thread-> _threadve raw_input-> input. Hattı beslemek için enter tuşuna basmanız gerekir. Herhangi bir tuş üzerinde yapmak istiyorsanız, getch'i kullanın .
Artyer

14

aşağıdaki kod benim için çalışıyor. OpenCV (içe aktarma cv2) gerektirir.

Kod, sürekli olarak basılan bir tuşu arayan sonsuz bir döngüden oluşur. Bu durumda 'q' tuşuna basıldığında program sona erer. Değişken bir değeri değiştirmek veya bir işlevi yürütmek gibi farklı eylemler gerçekleştirmek için diğer tuşlara (bu örnekte 'b' veya 'k') basılabilir.

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
İyi, ancak cv2 çok ağırdır, zaten başka bir şey için kullanmıyorsanız.
ogurets

1
neden VE 255 ile
Talespin_Kit

@Talespin_Kit & 0xff ”değişkeni maskeler, böylece yalnızca son 8 bitteki değeri bırakır ve tüm bitleri yok sayar. Temelde sonucun 0-255 aralığında olmasını sağlar. Not Bunu opencv'de hiç yapmıyorum ve işler iyi gidiyor.
eric

7

Python 3.7 için user297171'in çok güzel cevabını kopyalayıp değiştirdim, böylece test ettiğim Python 3.7'deki tüm senaryolarda çalışıyor.

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

Yanlış bir şey mi yapıyorum bilmiyorum ama bu döngüyü nasıl durduracağımı çözemiyorum? Bunu nasıl yaptın?
Mihkel

@Mihkel <Enter> tuşuna basmalısınız. Bu, döngünün çıkmasına neden olacaktır.
rayzinnz

Bu terbiyeli, ancak enter dışındaki tuşlara genelleme yapmıyor.
John Forbes

python2.7'de benim için çalışmıyor ama python3'te çalışıyor
crazjo

çok iş parçacığı yapmak da aklımda olan şey ama @ Keith'in yukarıdaki cevabını çok beğeniyorum. Yeterince basit ve net.
bağımlı

4

pyHook yardımcı olabilir. http://sourceforge.net/apps/mediawiki/pyhook/index.php?title=PyHook_Tutorial#tocpyHook%5FTutorial4

Klavye kancalarına bakın; bu daha geneldir - yalnızca KeyboardInterrupt'ı kullanmak yerine belirli klavye etkileşimleri istiyorsanız.

Ayrıca, genel olarak (kullanımınıza bağlı olarak) betiğinizi sonlandırmak için Ctrl-C seçeneğinin hala mevcut olduğunu düşünüyorum.

Ayrıca bir önceki soruya bakın: Python'da hangi tuşlara basıldığını tespit edin


1

Her zaman vardır sys.exit().

Python'un çekirdek kütüphanesindeki sistem kütüphanesi, prototipleme sırasında çok kullanışlı olan bir çıkış fonksiyonuna sahiptir. Kod şu satırlar boyunca olacaktır:

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

piton 3'te raw_inputile değiştirilirinput
Talha Anwar

1

Komut dosyasını belirli bir anahtarla sonlandırmak için rayzinnz'deki yanıtı değiştirdim, bu durumda çıkış anahtarı

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

Merhaba! Bu kod soruyu çözebilirken, sorunun nasıl ve neden çözüldüğüne dair bir açıklama da dahil olmak üzere , gönderinizin kalitesini artırmaya gerçekten yardımcı olur ve muhtemelen daha fazla oy almanıza neden olur. Sadece şimdi soran kişi için değil, gelecekte okuyucular için soruyu yanıtladığınızı unutmayın. Açıklamalar eklemek ve hangi sınırlamaların ve varsayımların geçerli olduğuna dair bir gösterge vermek için lütfen yanıtınızı düzenleyin .
Brian

1

Bu ipliği tavşan deliğinden aşağı doğru takip ederek, buna geldim, Win10 ve Ubuntu 20.04 üzerinde çalışıyor. Komut dosyasını öldürmekten ve belirli anahtarları kullanmaktan fazlasını istedim ve hem MS hem de Linux'ta çalışması gerekiyordu ..

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

Bu yararlı olabilir pynput with - 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

Bu, iş parçacıkları ve standart kitaplıklarda bulduğum çözümdür

Döngü, bir tuşa basılıncaya kadar devam eder Basılan
tuşu tek karakter dizisi olarak döndürür

Python 2.7 ve 3'te çalışır

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

girmek için 'ENTER' kullanın

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.