【问题标题】:How to respond to stdin while running another function?如何在运行另一个函数时响应标准输入?
【发布时间】:2019-04-04 13:23:06
【问题描述】:

我正在尝试编写一个 python 脚本,该脚本将在循环中打印出文本,并在打印任何内容时响应标准输入。 (我打算用这个python脚本与另一个程序交互)

我之前在 bash 中编写了一个脚本来执行此操作,现在想学习如何使用 python 执行此操作。我曾经使用以下脚本在 bash 中执行此操作;

#!/bin/sh

get_text () {
    echo "Some stuff here"
}

get_loop() {
    get_text
    /usr/bin/pactl subscribe | while read -r line ; do
        echo $line |
            grep -q -e "sink" -e "'change' on server #" && 
            get_text
    done
}

get_action () {
    case $1 in
        1)  # Left
            /usr/bin/pactl set-sink-mute @DEFAULT_SINK@ toggle > /dev/null 2>&1 ;;
        2) # Middle
            ;;
        3) # Right
            [ -x '/usr/bin/pavucontrol' ] && /usr/bin/pavucontrol > /dev/null 2>&1 & disown ;;
        4) # Scroll Up
            if [ "$_volm" -ge 100 ] ; then
                /usr/bin/pactl set-sink-volume @DEFAULT_SINK@ 100%  > /dev/null 2>&1
            else
                /usr/bin/pactl set-sink-volume @DEFAULT_SINK@ +5% > /dev/null 2>&1
            fi ;;
        5) # Scroll Down
            /usr/bin/pactl set-sink-volume @DEFAULT_SINK@ -5%  > /dev/null 2>&1 ;;
    esac
}

get_loop & while read button ; do get_action $button ; done

这就像我想要的那样工作。到目前为止,在 python 中,我有这个;

#!/usr/bin/python
import sys
import time

def respond(x=0):
    while True:
        x += int(sys.stdin.readline())
        print(x)

def loop(t=1):
    x = 0
    while True:
        x += 1
        print('Delay is ' + str(t) + ' and looped ' + str(x) + ' times.')
        time.sleep(t)

loop(1)
respond(0)

这些功能单独工作,但我如何让它们同时工作?我正在考虑做一个循环,然后等到事件或标准输入上有什么东西;但我可以这样做吗?

(有关我正在尝试执行的任务的详细信息,我正在尝试将pulseaudio的blocklet写到i3blocks。脚本打印出一行JSON格式的文本,由进程读取,信息为打印在我的状态栏上。每次pulseaudio发生变化时,我的脚本都会打印一条更新的行。i3blocks还发送一个JSON格式的字符串,这是发生鼠标单击事件时的信息,我决定为此切换静音,增加/减少音量或启动一个程序。我确实让它与 bash 一起工作,但我也在学习 python,将我的 bash 脚本转换为 python 是一个玩具项目,我必须深入研究这些东西。)

【问题讨论】:

  • 如果你想同时运行两个函数,你可以使用线程。
  • 线程或多处理。否则 GIL 会阻止你这样做。
  • 这就是我所担心的。有没有办法在某个事件的无限循环中发出继续,或者在标准输入上发出什么?

标签: python stdin


【解决方案1】:

你的 bash 文件永远不会接受任何输入,也不会输入 python 文件,因为你有一个无限循环并且永远不会真正调用响应函数。

【讨论】:

  • 我简化了我的 bash 函数作为演示;我会用原来的更新它。
【解决方案2】:

Bash 脚本最后一行中的& 异步启动get_loop。在 Python 中实现此目的的一种方法是 threading 模块:

#!/usr/bin/env python3
import sys
import time
from itertools import count
from threading import Thread


def respond():
    total_sum = 0
    while True:
        total_sum += int(sys.stdin.readline())
        print(total_sum)


def loop(delay):
    for i in count():
        print(f'Delay is {delay} and looped {i} times.')
        time.sleep(delay)


def main():
    thread = Thread(target=loop, args=[1])
    thread.daemon = True
    thread.start()
    respond()


if __name__ == '__main__':
    main()

其他方法是使用multiprocessing 模块,该模块可用于在另一个进程中启动其中一个功能,这正是 Bash 对& 所做的实际操作。或者 asyncio 模块和 Python 的 async/await 关键字。

【讨论】:

    猜你喜欢
    • 2021-03-03
    • 1970-01-01
    • 1970-01-01
    • 2013-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多