Почему не работает функция?

Итак, у меня есть несколько проблем с кодом в разделе:

  1. когда клавиша, выбранная в поле со списком, удерживается нажатой, она продолжает печатать «Вы нажали ее», есть ли способ избежать этого?
  2. Когда я нажимаю горячую клавишу set, метка меняется, но цикл while в процессе () не меняется, предполагается, что он выполняет процесс задач, но я упростил его для печати для этого вопроса.
run = False

def press():
    global run
    while True:
        if keyboard.read_key(hotCombo.get()):
            print("You Pressed It")
            run = not run
            keyboard.wait(hotCombo.get())
            if run == True:
                status["text"] = "Working"
            else:
                status["text"] = "Not Working"
            
def process():
    while run == True:
        print("runnning")

Повозился с ним и нашел больше проблем

Я закончил с этим, но пока он печатает run, я не могу его остановить

def process():
    global run
    while True:
        if keyboard.read_key(hotCombo.get()):
            print("kijanbdsjokn")
            run = not run
            keyboard.wait(hotCombo.get())
            if run == True:
                status["text"] = "Working"
            else:
                status["text"] = "Not Working"
            while run == True:
                print("run")
                time.sleep(1)
            

Я предполагаю, что вы звоните autofisher куда-то. Подумайте о том, что происходит, когда вы это делаете. Поскольку run имеет значение False, цикл немедленно завершится, и функция вернется. Вам нужно было бы иметь это в отдельном потоке, чтобы он работал, и вам нужно, чтобы он был while True:, чтобы работать вечно. Что, конечно, ужасная идея, потому что она сожрет 100% процессора. Никакой другой код Python не будет работать.

Tim Roberts 19.03.2022 07:45

Это не похоже на настоящую tkinter программу. Добавление собственного цикла событий внутри (как выглядит) обратного вызова, как правило, не очень хорошая идея.

Roland Smith 19.03.2022 07:53

@RolandSmith Да, несколько человек сказали мне, что в разногласиях по python сказали мне это, но на самом деле они не указали мне правильный путь. Могу я спросить, почему я не могу просто интегрировать tkinter в работающий скрипт python, используя потоки?

That Guy 19.03.2022 08:00

@TimRoberts Нет, я на самом деле нигде не вызываю autofisher, я просто предположил, что то, что внутри, будет работать, потому что функция press запускается без необходимости ее вызова. Есть ли способ запустить его только при нажатии горячей клавиши, а не внутри while True

That Guy 19.03.2022 08:03

@OGXirvin Ответ на этот вопрос настолько длинный, что я превратил его в ответ ниже. :-)

Roland Smith 19.03.2022 09:03
press не будет работать, если вы его не вызовете. Я гарантирую это. Либо вы его вызываете, либо передаете в качестве параметра какой-либо другой функции, которая его вызывает.
Tim Roberts 20.03.2022 00:29

@TimRoberts Я не уверен, но я использую потоки, вызывает ли это функцию?

That Guy 20.03.2022 03:23

Если делать x = threading.Thread(target=press) и x.start(), то да, конечно, будет вызываться.

Tim Roberts 20.03.2022 03:41

@TimRoberts да, у меня есть эта настройка, вы можете увидеть весь мой код в stackoverflow.com/questions/71543616/…

That Guy 20.03.2022 03:44
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
9
79
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Один из способов обработки вашего ключа — превратить его в двухфазный цикл:

def press():
    global run
    while True:
        while not keyboard.read_key(hotCombo.get()):
            time.sleep(0.2)
        run = True
        status["text"] = "Working"
        while keyboard.read_key(hotCombo.get()):
            print("running")
            time.sleep(0.2)
        run == False
        status["text"] = "Not Working"

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

That Guy 19.03.2022 08:10
Ответ принят как подходящий

Can I ask why I cant just integrate tkinter into a working python script using threading?

Сценарий Python обычно линейный. Вы делаете что-то последовательно, а затем уходите.

В программе tkinter ваш код состоит из трех вещей.

  • Код для настройки окна и виджетов.
  • Инициализация глобальных переменных (на самом деле не имеет значения, скрываете ли вы их в экземпляре класса; они по-прежнему являются глобальными).
  • Большинство из них будут функциями/методами, которые вызываются как обратные вызовы из tkinter, когда они находятся в mainloop.

Таким образом, в tkinter программе большая часть вашего кода представляет собой гость в mainloop. Где он исполняется небольшими кусочками в ответ на события. Это совсем другая программа. Это называлось программированием событийный или сообщение на основе задолго до того, как это стало крутым в веб-серверах и фреймворках.

Итак, можете ли вы интегрировать скрипт в программу tkinter? Да, это возможно. Есть в основном три способа сделать это;

  • Разделите код на небольшие части, которые можно вызывать через after тайм-ауты. Это включает в себя наибольшую реорганизацию вашего кода. Чтобы графический интерфейс оставался отзывчивым, обработчики событий (например, тайм-ауты) не должны занимать слишком много времени; 50 мс кажется разумным верхним пределом.
  • Запустите его в другом потоке. Мы рассмотрим это более подробно ниже.
  • Запустите его в другом процессе. широко аналогичен запуску в потоке (API threading.Thread и multiprocessing.Process почти одинаковы по дизайну). Самая большая разница заключается в том, что связь между процессами должна осуществляться явно, например, через Queue или Pipe.

Есть некоторые вещи, которые вы должны учитывать при использовании дополнительных потоков, особенно в программе tkinter.

1) версия Python

Вам нужно использовать Python 3. Это не будет хорошо работать в Python 2 по причинам, которые выходят за рамки этого ответа. Лучшее вытеснение потоков в Python 3 — большая часть этого.

2) Многопоточная сборка tkinter

tkinter (или, скорее, базовый интерпретатор tcl) должен быть построен с включенной поддержкой многопоточности. Я так понимаю, что официальные python.org сборки для ms-windows есть, но кроме YMMV. В некоторых UNIX-подобных системах, таких как Linux или *BSD, системы пакетов/портов предоставляют вам выбор.

3) Превратите свой код в функцию

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

4) Сделайте функцию удобной для потоков

Вы, вероятно, захотите иметь возможность прерывать для этого потока, если это занимает слишком много времени. Таким образом, вы должны адаптировать его, чтобы регулярно проверять, должно ли оно продолжаться. Проверка того, является ли глобальный объект с именем runTrue, является одним из методов. Обратите внимание, что API threading позволяет нет просто завершить поток.

5 Обычные опасности многопоточности

Вы должны быть осторожны с одновременным изменением виджетов или глобальных переменных из обоих потоков.

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

Например, посмотрите на модификацию глобальной функции modify:

In [1]: import dis

In [2]: data = []
Out[2]: []

In [3]: def modify():
   ...:     global data
   ...:     newdata = [1,2,3]
   ...:     data = newdata
   ...:     

In [4]: dis.dis(modify)
  3           0 BUILD_LIST               0
              2 LOAD_CONST               1 ((1, 2, 3))
              4 LIST_EXTEND              1
              6 STORE_FAST               0 (newdata)

  4           8 LOAD_FAST                0 (newdata)
             10 STORE_GLOBAL             0 (data)
             12 LOAD_CONST               0 (None)
             14 RETURN_VALUE

Посмотрите, как новый список строится отдельно, и только когда он завершен, он назначается глобальному. (Это было не случайно.)

Требуется всего одна инструкция байт-кода (STORE_GLOBAL), чтобы установить глобальную переменную во вновь созданный список. Таким образом, ни в коем случае значение data не может быть двусмысленным.

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

IIRC, в настоящее время поток прерывается каждые 15 мс. Таким образом, изменение, которое занимает больше времени, является гарантировано для вытеснения. Как и любая задача, которая отбрасывает GIL для ввода-вывода.

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

Это помогает, если, например. виджет или переменная — это только модифицированный из одна нить и только читать из всех остальных потоков.

Другие вопросы по теме