[Python] Перехватить ctrl-c в консоли

feliks28

Хочется реализовать "делать в цикле, пока не нажато ctrl-c". Как это сотворить в консоли наименее безболезненно?
Не под винду.

sergeikozyr


try:
.......
except KeyboardInterrupt:
print 'Fuck!'

Andbar

А как при этом вернуть управление исполнявшемуся коду?

klyv

On Error Resume Next  

Andbar

Не нашёл таких слов в документации по питону 2.5, а доки по 2.6 под руками нет.
Но вообще эта строчка мне почему-то вижуалбейсик напоминает...
Я вот почему спрашиваю: обычно отработчик(и) сигналов нажатия ^C/^Break выполняе(ю)тся асинхронно. И есть возможность запрограммировать какую-нибудь хитрую недефолтную реакцию (например, прерывание выполнения после завершения текущей стадии расчётов при однократном нажатии ^C).

klyv

:)
такая обработка ошибок есть только в VB (из тех, что я знаю). После получения Exception вернуться штатными средствами в точку, где он возник, невозможно ни в одном языке.
как-то точно можно перехватывать ctrl-c без исключения...

klyv

м?

Andbar

ага, это, по идее, более логичный вариант...

sergeikozyr

А как при этом вернуть управление исполнявшемуся коду?
ему надо делать в цикле пока не нажато, так что предложенный вариант вполне подходит.

Andbar

ему надо делать в цикле пока не нажато, так что предложенный вариант вполне подходит.
Вовсе не обязательно. Может ему захочется цикл нормально завершить, а не прерывать в случайном месте?

sergeikozyr

Вовсе не обязательно. Может ему захочется цикл нормально завершить, а не прерывать в случайном месте?
бля, не знаешь питона, лучше бы не влезал. Есть finally.

Dasar

лучше бы не влезал. Есть finally.
это не то

pitrik2

После получения Exception вернуться штатными средствами в точку, где он возник, невозможно ни в одном языке.
эээ
это континуэйшен?
он же есть во всяких там лиспах
и в сишарпе вродь писали чего-то подобное есть

agaaaa

Вроде нет такого в C#
Ну или я уже больше пяти лет плохо читаю документацию.

sergeikozyr

Ну или я уже больше пяти лет плохо читаю документацию.
yield?

klyv

yield?
да-да, там ещё много есть слов.
но причём тут это?!

klyv

это континуэйшен?
ээ... нет?

agaaaa

Нет, ну продолжения есть в любом языке, где можно функции по ссылке передавать в общем-то.
Возврат в точку исключения можно сделать, но это нетривиально и, вероятно, не портируемо.

Dasar

Возврат в точку исключения можно сделать, но это нетривиально и, вероятно, не портируемо.
в первую очередь, это чревато труднообнаруживаемыми ошибками, из-за того, что когда вызывается обработчик ошибки контекст может быть полностью произвольным.
соответственно, в обработчике ошибки, получается вообще не понятно, на что можно расчитывать, а на что нельзя, и соответственно почти польностью нельзя использовать внешнее окружение.

feliks28

Хм. А если то же самое, но для ctrl-break?
Прерывание не генерит, signal.SIGBREAK существует только под винду....

sergeikozyr

Хм. А если то же самое, но для ctrl-break?
А что делает Ctrl+Break?

Andbar

А что делает Ctrl+Break?
Это альтернатива ^C, но ещё со времён DOS'а она распознавалась как отдельный сигнал (в смысле, её, вроде, можно было отдельно отключить, а обработка их как сигналов уже в винде появилась).

feliks28

А что делает Ctrl+Break?
Да вот хочется как раз, чтобы делало то, что попросят :)
Тред появился именно потому, что после нескольких часов гугления ничего, чтобы обрабатывало сочетания клавиш в консоли я не нашел... Только для gui

pilot

Еще вариант:
Заведи отдельный тред с задачкой. Сигналы с консоли (exceptions) придут в главный тред. Там их и обработай.

feliks28

Не понял зачем нужен отдельный тред, но в любом случае:
А уже упомянутое ctrl-break или, например, неупомянутое alt-shift-K какое исключение выбросят?

Andbar

Сигналы с консоли (exceptions) придут в главный тред. Там их и обработай.
Хз как в *nix, в винде они приходят отдельным потоком, соответственно, их обработчик будет работать не прерывая работу основного потока.

Andbar

А уже упомянутое ctrl-break или, например, неупомянутое alt-shift-K какое исключение выбросят?
Проверь, какие вообще проблемы?
C:\temp>type 1.py
import sys
from time import sleep

try:
sleep(10)
except BaseException:
print sys.exc_info[0]
C:\temp>python 1.py
<type 'exceptions.KeyboardInterrupt'>

C:\temp>python 1.py
^C

C:\temp>python 1.py


C:\temp>python --version
Python 2.5
Первый запуск прерван по ^C, второй по ^Break, третий пытался прервать по Alt+Shift+K, которого в винде нет :p
Как видно, у питона 2.5 под винду весьма странный взгляд на ^Break (зачем-то отображает его как ^C).

feliks28

Проверь, какие вообще проблемы?

Да в общем-то никаких. Как проблем так и исключений

Andbar

Короче, вот код на C, ловящий ^C и ^Break:
 
#include<stdio.h>
#include<signal.h>

void handler(int num)
{
printf(" %d\n", num);
signal(num, handler);
}

main
{
int i;

signal(SIGINT, handler);
signal(SIGBREAK, handler);

for(i=0; i<100000; ++i)
printf("\r%d", i);
}
Если я правильно понимаю, аналогом для него на питоне будет следующий код:
from sys import *
from signal import *

def handler(num, stack):
stdout.write(" %d\n"%num)
# signal(num, handler)

signal(SIGINT, handler)
signal(SIGBREAK, handler)

for i in range(1,100000):
stdout.write("\r%d"%i)
На счёт закоменченой строки: почему-то работает и без неё.

feliks28

Чуть выше я писал, что
signal.SIGBREAK существует только под винду

Andbar

Если под *nix работает ^Break (как под виндой то для него, наверное, должен быть назначен какой-нибудь сигнал? Через putty ^Break ничего не прерывает.

feliks28

Если под *nix работает ^Break (как под виндой)
А оно и не работает

Andbar

А оно и не работает
ну тогда какие проблемы остались?

feliks28

ну тогда какие проблемы остались?
Эммм... Проблема обработки нажатия клавиш в консоли.

Andbar

Эммм... Проблема обработки нажатия клавиш в консоли.
Т.е., ты хочешь любые клавиши ловить/обрабатывать асинхронно, не прерывая исполнение основного потока?

feliks28

Т.е., ты хочешь любые клавиши ловить/обрабатывать асинхронно, не прерывая исполнение основного потока?
В идеале.
Читать из "буфера нажатий клавиш" (или как там это в сях называлось) тоже сойдет. Нашелся бы такой буфер...
И это в консоли и не windows-зависимое решение...

feliks28

Кстати, tty.setcbreak а потом читать из sys.stdin я попробовал, и у меня не особо получилось: сильно выборочно для Ctrl-буква, лучше для Alt-буква, вообще никак для Ctrl-Break (Кстати, узнал, что Ctrl-j = Enter )
Так что sys.stdin, к сожалению, не вариант...

Andbar

вообще никак для Ctrl-Break
а он тебе зачем? У меня сложилось впечатление, что putty его вообще не передаёт...

klyv

а если curses?

bleyman

> Ctrl-j = Enter
Ну как бы j - десятый символ. http://en.wikipedia.org/wiki/C0_and_C1_control_codes
А насчёт питона и ctrl-c, он как-то хитроумно всё делал, типа у него был свой хандлер, который тупо выставлял флажок, который периодически проверялся и для которого была даже специальная сишная функция в апи (в смысле, когда долгие вычисления делаешь, неплохо её вызывать). Почитай мануал, что ли!

feliks28

  
насчёт питона и ctrl-c
Да мы уже давно не про этот частный случай...
Почитай мануал, что ли
Я раньше был молодой и наивный и ходил и читал мануалы, когда посылали. Но того что мне нужно там не оказывалось, а было только что-то отдаленно похожее, о чем поставленная мной проблема напомнила "пославшему в мануал", но работающее совершенно иначе и к тому что нужно мне неприменимое.
Какой раздел какого мануала читать? Там где я читал до этого, про обработку клавиш в консоли не упоминалось.

margadon

ну и читай из консоли клавиши в отдельном потоке :)

feliks28

ну и читай из консоли клавиши в отдельном потоке

Проблема не в отдельном потоке, проблема в чтении клавиш.

bleyman

слушай, а используй pygame, в самом деле. Или посмотри, как они там это делают.

feliks28

pygame

В консоли?

cascad

Если еще актуально, то вот рабочий под python 3.6.
import keyboard
keyboard.add_hotkey('ctrl+c', print, args=('triggered', 'ctrl+c'))
keyboard.wait()
Оставить комментарий
Имя или ник:
Комментарий: