编程语言
首页 > 编程语言> > 中止对python交互式控制台的评估

中止对python交互式控制台的评估

作者:互联网

我正在编写自己的python代码编辑器和终端以取乐,并在现有程序中实现它以增加可写性.

现在,我发现了一个问题,我不知道如何在代码运行后停止评估.那怎么办?

这是我的实现:

import code
import contextlib
import sys
from io import StringIO
import copy


@contextlib.contextmanager
def capture():
    oldout,olderr = sys.stdout, sys.stderr
    try:
        out=[StringIO(), StringIO()]
        sys.stdout,sys.stderr = out
        yield out
    finally:
        sys.stdout,sys.stderr = oldout, olderr
        out[0] = out[0].getvalue()
        out[1] = out[1].getvalue()


class PythonTerminal(code.InteractiveConsole):

    def __init__(self, shared_vars):
        self.shared_vars_start = copy.deepcopy(shared_vars)
        self.shared_vars = shared_vars
        super().__init__(shared_vars)
        self.out_history = []

    def run_code(self,code_string):
        with capture() as out:
            self.runcode(code_string)

        self.out_history.append(out)
        return out

    def restart_interpreter(self):
        self.__init__(self.shared_vars_start)

    def stop(self):
        raise NotImplementedError

if __name__ == '__main__':
    a = range(10)
    PyTerm = PythonTerminal({'Betrag': a})
    test_code = """
for i in range(10000):
    for j in range(1000):
        temp = i*j
print('Finished'+str(i))
"""
    print('Starting')
    t = threading.Thread(target=PyTerm.run_code,args=(test_code,))
    t.start()

    PyTerm.stop()
    t.join()
    print(PyTerm.out_history[-1]) # This line should be executed immediately and contain an InterruptError

目的是停止评估,但解释器仍然有效,例如ctrl c.

解决方法:

我认为您无法轻易杀死Python中的线程.但是,您可以杀死一个multiprocessing.Process.因此,您可以使用单独的过程在控制台中执行代码并通过multiprocessing.Queue与之通信.为此,我实现了一个TerminalManager类,该类可以在单独的进程中执行PythonTerminal.run_code并杀死它.请参阅下面的修改后的代码.对此的一个主要缺点是,InteractiveConsole的本地语言在两次调用之间不会保持不变.我添加了一个将本地人存储到搁置文件中的黑客(这可能很糟糕).想到的最快的事情.

import code
import contextlib
import sys
from io import StringIO
import copy
import threading
import multiprocessing
import json
import shelve

class QueueIO:
    """Uses a multiprocessing.Queue object o capture stdout and stderr"""
    def __init__(self, q=None):

        self.q = multiprocessing.Queue() if q is None else q

    def write(self, value):
        self.q.put(value)

    def writelines(self, values):
        self.q.put("\n".join(str(v) for v in values))

    def read(self):
        return self.q.get()

    def readlines(self):
        result = ""
        while not self.q.empty():
            result += self.q.get() + "\n"


@contextlib.contextmanager
def capture2(q: multiprocessing.Queue):
    oldout,olderr = sys.stdout, sys.stderr
    try:
        qio = QueueIO(q)
        out=[qio, qio]
        sys.stdout,sys.stderr = out
        yield out
    finally:
        sys.stdout,sys.stderr = oldout, olderr


class PythonTerminal(code.InteractiveConsole):

    def __init__(self, shared_vars):
        self.shared_vars_start = copy.deepcopy(shared_vars)
        self.shared_vars = shared_vars
        super().__init__(shared_vars)
        self.out_history = []

    def run_code(self,code_string, q):
        # retrieve locals
        d = shelve.open(r'd:\temp\shelve.pydb')
        for k, v in d.items():
            self.locals[k] = v

        # execute code
        with capture2(q) as out:
            self.runcode(code_string)            

        # store locals
        for k, v in self.locals.items():
            try:
                if k != '__builtins__':
                    d[k] = v
            except TypeError:
                pass
        d.close()


    def restart_interpreter(self):
        self.__init__(self.shared_vars_start)


class TerminalManager():

    def __init__(self, terminal):
        self.terminal = terminal
        self.process = None
        self.q = multiprocessing.Queue()        

    def run_code(self, test_code):
        self.process = multiprocessing.Process(
            target=self.terminal.run_code,args=(test_code, self.q))
        self.process.start()

    def stop(self):
        self.process.terminate()
        self.q.put(repr(Exception('User interupted execution.')))

    def wait(self):
        if self.process.is_alive:
            self.process.join()
        while not self.q.empty():
            print(self.q.get())    

if __name__ == '__main__':
    import time
    a = range(10)
    PyTerm = PythonTerminal({'Betrag': a})
    test_code = """
import time
a = 'hello'
for i in range(10):
    time.sleep(0.2)
    print(i)
print('Finished')
"""
    mgr = TerminalManager(PyTerm)
    print('Starting')
    mgr.run_code(test_code)    
    time.sleep(1)
    mgr.stop()
    mgr.wait()

    test_code = """
import time
_l = locals()

print('a = {}'.format(a))  
for i in range(10):
    time.sleep(0.1)
    print(i)
print('Finished')
"""
    print('Starting again')
    mgr.run_code(test_code)        

    mgr.wait()

标签:standard-library,python
来源: https://codeday.me/bug/20191111/2021501.html