在另一个线程中回答 python 输入
Answer python input from within on another thread
我想从代码中 python 上同一进程的另一个线程回答 input()
。
这是代码:
import sys
import threading
def threaded(fn):
def wrapper(*args, **kwargs):
thread = threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True)
thread.start()
return thread
return wrapper
@threaded
def answer():
time.sleep(2)
sys.stdin.write('to be inputed')
answer()
x = input('insert a value: ')
print(f'value inserted: {x}') # excpeted print: 'value inserted: to be inputed'
但我认为这不可能,因为我收到此错误:
Exception in thread Thread-1:
Traceback (most recent call last):
File "teste.py", line 80, in answer
sys.stdin.write('to be inputed')
io.UnsupportedOperation: not writable
很难解释为什么我想要那个,但有时用户会输入值,有时它会来自另一个输入源(电报)。所以这第二个线程应该能够输入值并释放代码执行。
我也无法更改代码的 input()
部分,因为它来自库内部,所以它需要这样:input('insert a value: ')
有办法实现吗?
简单的答案是,如果您将 sys.stdin
替换为您自己的变量,那么 input
将使用它。
但是,您已经丢失了原来的 stdin
,因此您需要启动一个新进程来侦听用户输入,因为您说:
but sometimes the user will input the value
这需要是另一个进程而不是线程,因为当您想要恢复原始标准输入时需要终止它,并且终止进程会在中途中断它-readline
。
这是实现了模拟对象的代码的工作版本。 with
块内的区域是标准输入被替换的地方。
import sys
import time
import multiprocessing
import threading
class MockStdin:
def __init__(self):
self.queue = None
self.real_stdin = sys.stdin
self.relay_process = None
def readline(self):
# when input() is called, it calls this function
return self.queue.get()
def writeline(self, s):
# for input from elsewhere in the program
self.queue.put(s)
def relay_stdin(self):
# for input from the user
my_stdin = open(0) # this is a new process so it needs its own stdin
try:
while True:
inp = my_stdin.readline()
self.queue.put(inp)
except KeyboardInterrupt:
# when killed, exit silently
pass
def __enter__(self):
# when entering the `with` block, start replace stdin with self and relay real stdin
self.queue = multiprocessing.Queue()
self.relay_process = multiprocessing.Process(target=self.relay_stdin)
self.relay_process.start()
sys.stdin = self
def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
# when exiting the `with` block, put stdin back and stop relaying
sys.stdin = self.real_stdin
self.relay_process.terminate()
self.relay_process.join()
def __getstate__(self):
# this is needed for Windows - credit to Leonardo Rick for this fix
self_dict = self.__dict__.copy()
del self_dict['real_stdin']
return self_dict
def threaded(fn):
def wrapper(*args, **kwargs):
thread = threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True)
thread.start()
return thread
return wrapper
if __name__ == '__main__':
mock = MockStdin()
@threaded
def answer():
time.sleep(2)
# use mock to write to stdin
mock.writeline('to be inputed')
answer()
with mock:
# inside `with` block, stdin is replaced
x = input('insert a value: ')
print(f'\nvalue inserted: {x}')
answer()
# __enter__ and __exit__ can also be used
mock.__enter__()
x = input('insert a value: ')
print(f'\nvalue inserted: {x}')
mock.__exit__()
# now outside the `with` block, stdin is back to normal
x = input('insert another (stdin should be back to normal now): ')
print(f'value inserted: {x}')
我想从代码中 python 上同一进程的另一个线程回答 input()
。
这是代码:
import sys
import threading
def threaded(fn):
def wrapper(*args, **kwargs):
thread = threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True)
thread.start()
return thread
return wrapper
@threaded
def answer():
time.sleep(2)
sys.stdin.write('to be inputed')
answer()
x = input('insert a value: ')
print(f'value inserted: {x}') # excpeted print: 'value inserted: to be inputed'
但我认为这不可能,因为我收到此错误:
Exception in thread Thread-1:
Traceback (most recent call last):
File "teste.py", line 80, in answer
sys.stdin.write('to be inputed')
io.UnsupportedOperation: not writable
很难解释为什么我想要那个,但有时用户会输入值,有时它会来自另一个输入源(电报)。所以这第二个线程应该能够输入值并释放代码执行。
我也无法更改代码的 input()
部分,因为它来自库内部,所以它需要这样:input('insert a value: ')
有办法实现吗?
简单的答案是,如果您将 sys.stdin
替换为您自己的变量,那么 input
将使用它。
但是,您已经丢失了原来的 stdin
,因此您需要启动一个新进程来侦听用户输入,因为您说:
but sometimes the user will input the value
这需要是另一个进程而不是线程,因为当您想要恢复原始标准输入时需要终止它,并且终止进程会在中途中断它-readline
。
这是实现了模拟对象的代码的工作版本。 with
块内的区域是标准输入被替换的地方。
import sys
import time
import multiprocessing
import threading
class MockStdin:
def __init__(self):
self.queue = None
self.real_stdin = sys.stdin
self.relay_process = None
def readline(self):
# when input() is called, it calls this function
return self.queue.get()
def writeline(self, s):
# for input from elsewhere in the program
self.queue.put(s)
def relay_stdin(self):
# for input from the user
my_stdin = open(0) # this is a new process so it needs its own stdin
try:
while True:
inp = my_stdin.readline()
self.queue.put(inp)
except KeyboardInterrupt:
# when killed, exit silently
pass
def __enter__(self):
# when entering the `with` block, start replace stdin with self and relay real stdin
self.queue = multiprocessing.Queue()
self.relay_process = multiprocessing.Process(target=self.relay_stdin)
self.relay_process.start()
sys.stdin = self
def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
# when exiting the `with` block, put stdin back and stop relaying
sys.stdin = self.real_stdin
self.relay_process.terminate()
self.relay_process.join()
def __getstate__(self):
# this is needed for Windows - credit to Leonardo Rick for this fix
self_dict = self.__dict__.copy()
del self_dict['real_stdin']
return self_dict
def threaded(fn):
def wrapper(*args, **kwargs):
thread = threading.Thread(target=fn, args=args, kwargs=kwargs, daemon=True)
thread.start()
return thread
return wrapper
if __name__ == '__main__':
mock = MockStdin()
@threaded
def answer():
time.sleep(2)
# use mock to write to stdin
mock.writeline('to be inputed')
answer()
with mock:
# inside `with` block, stdin is replaced
x = input('insert a value: ')
print(f'\nvalue inserted: {x}')
answer()
# __enter__ and __exit__ can also be used
mock.__enter__()
x = input('insert a value: ')
print(f'\nvalue inserted: {x}')
mock.__exit__()
# now outside the `with` block, stdin is back to normal
x = input('insert another (stdin should be back to normal now): ')
print(f'value inserted: {x}')