将基于exec()的Python代码转换为iPython API

将基于exec()的Python代码转换为iPython API,python,jupyter-notebook,ipython,jupyter,Python,Jupyter Notebook,Ipython,Jupyter,我正在做一个个人项目,涉及到一个类似于Jupyter笔记本的复制品。现在,我有一个Cell类,它存储用户的代码输入,并在被告知时执行该代码。通过使用Python的exec()函数,每个单元都在自己的线程中执行 出于几个原因,我想通过实现iPython的cell结构来替代此功能,主要是因为很难/不可能从Python脚本中杀死线程,因此我不能在不杀死主线程的情况下中断代码执行 然而,iPython的API似乎没有任何形式的单元、执行、中断或Jupyter UI提供的任何其他功能的集成。如果我想开始将

我正在做一个个人项目,涉及到一个类似于Jupyter笔记本的复制品。现在,我有一个
Cell
类,它存储用户的代码输入,并在被告知时执行该代码。通过使用Python的
exec()
函数,每个
单元都在自己的线程中执行

出于几个原因,我想通过实现iPython的cell结构来替代此功能,主要是因为很难/不可能从Python脚本中杀死线程,因此我不能在不杀死主线程的情况下中断代码执行

然而,iPython的API似乎没有任何形式的单元、执行、中断或Jupyter UI提供的任何其他功能的集成。如果我想开始将我的程序转换为使用iPython的API而不是janky方法,我从哪里开始呢

以下是简略代码:

将networkx导入为nx
将matplotlib.pyplot作为plt导入
从io导入StringIO
从networkx导入算法
类别单元格:
定义初始化(自我,
姓名!,
content\u type=“python”,
内容=“”,
前十名,
左(10):
"""
:参数名称\单元格的名称
:param content\u type\单元格中内容的类型(标记或python)
:param content\单元格的内容,标记或python代码
:param top\前端单元格的顶部位置
:param left\:前端单元格的左位置
"""
self.name=名称_
self.content\u type=内容类型_
self.content=内容_
self.output=“”
self.top=top_
self.left=左_
def执行(自我):
#执行此单元格的内容
如果不是self.content_type==“python”:
返回
全球执行官
ex_vars_copy=exec_vars.copy()
尝试:
打印(“”)
执行官(self.content,ex_vars_copy)
例外情况除外:
打印(“单元格中出现异常”+self.name)
打印(例外)
执行变量更新(执行变量副本)
类图:
定义初始化(自身,父级):
“”“包含单元格对象并遍历它们以执行。”“”
#Networkx有向图
self.graph=nx.DiGraph()
self.parent=parent
#Dict跟踪单元格名称与networkx节点名称
self.names_to_indeces={}
#单元格创建的变量字典
全球执行官
exec_vars={}
#文本对象
self.ti=TextIO()
自动执行=错误
def bfs_遍历_执行(自):
导入时间
如果len(self.get_all_cells_edges()[0])==0:
返回
self.executing=True
root\u cell=self.get\u cell(“,0)
root=threading.Thread(target=root\u cell.execute)
std\u file\u out=根\u cell.name
root.start()
root.join()
std_file_out+=根单元格.output
n_u=self.graph.neights(0)
邻居=[n表示n中的n]
而邻居:
新邻居=[]
进程=[]
对于邻居中的n:
邻居单元=self.get单元(self.get单元查找表()[n].strip())
邻居=线程.Thread(目标=邻居\单元.execute)
邻居。开始()
进程。追加(邻居)
新的_邻居.extend([self.graph.neights(n)]中的i代表i)
对于过程中的过程:
proc.join()
对于邻居中的n:
时间。睡眠(.05)
邻居=self.get\u单元格(self.get\u查找表()[n])
标准文件输出+=“\n”
std_file_out+=neighbor.output
邻居=新邻居
自动执行=错误

我对此进行了一些思考。我认为iPythonAPI似乎有点臃肿,设计得不是特别好——至少在我的用例中是这样(与您的类似)。实现一个可供外部进程访问的简单消息传递队列是相当简单的,您可以通过多种不同的pythonic方法从中执行代码

还有相当多的辅助python库可以模拟一些可以在Jupyter中完成的完成/格式化

我认为你的简奇方法很好

就线程而言,我使用的是异步IO/协同路由,因此中断是相当自然和简单的。一般来说,线程在python中的意义不大,因为它们的并行性较差,并且浪费时间锁定和释放GIL


如果我需要多核访问,我通常会使用多进程,但这超出了本问答的范围。

非常酷!我正在做一些非常类似的事情,尽管我正在使用cytoscape进行图形编辑。看看吧,真是太棒了。我大部分时间只是执行所有新鲜的东西(没有驻留内核),但现在处理的是一些更加iPythonish的东西。遗憾的是,ipythonapi的文档记录非常糟糕。例如,我现在正在研究用法。这个答案根本不能评估我所说的问题。我需要转换成iPython,不管怎样,
exec()
都不起作用。嗯,怎么不起作用?我发现它工作得很好,尽管我在将代码保存到文件时使用了导入/重新加载用例。我使用changeStream/mongodb来侦听要执行的异步任务。我在github上做了一个搜索,除了jupyter,我没有看到其他人使用iPythonAPI,这并不奇怪。我认为这更像是jupyter的内部API。还有PromptToolkit、bpython、mypython、ptpython和xonsh