Package: dynamic-links
Dynamic Links安装方法pipinstalldynamic-links简介概述Dynamic Links 是一个 python 元素管理框架，可以方便地构建 benchmark 等应用。使用 Dynamic Links，用户仅需先定义应用中所需的元素、再定义执行逻辑，最后定义每个元素有哪些具体的 python 对象可选，即可通过 Web 页面配置并执行应用。例子fromdlframeimportWebManagerdeff1(x):print('f1',x)deff2(x):print('f2',x)# 定义元素管理器withWebManager()asmanager:# 定义元素 + 定义元素可选的 python 对象func=manager.register('func',{'function1':f1,'function2':f2})# 定义框架执行逻辑func('test')运行程序，即可通过前端选择执行f1或f2。另一个例子fromdlframeimportWebManagermanager=WebManager()# 定义元素可选的 python 对象@manager.register('func','function1')# 也可 @manager.register('func') 会自动以 f1 作为选项名称deff1(x):print('f1',x)# 定义元素可选的 python 对象@manager.register('func','function2')deff2(x):print('f2',x)# 定义元素管理器withmanager:# 定义元素func=manager['func']# 定义框架执行逻辑func('test')与上一个例子完全等价。又一个例子fromdlframeimportWebManagerdeff1(x):print('f1',x)deff2(x):print('f2',x)# 定义元素管理器withWebManager()asmanager:# 定义元素可选的 python 对象manager.register('func','function1',f1)manager.register('func','function2',f2)# 定义元素func=manager['func']# 定义框架执行逻辑func('test')与上一个例子完全等价。更复杂的例子Dynamic Links 可以很方便地构建 benchmark 等应用。例如，如果要实现一个机器学习算法的简易框架，评估不同模型在不同参数下的各种指标，可以编写如下程序：fromdlframeimportWebManager# 定义元素管理器withWebManager()asmanager:# 定义元素 + 定义元素可选的 python 对象dataset=manager.register('数据集',{'iris':IrisDataset(),'watermelon':WatermelonDataset()})split_ratio=manager.register('数据分割比例',{'10%':0.1,'30%':0.3})Splitter=manager.register('数据分割器',{'k-fold':KFoldSplitter,'random':RandomSplitter})Model=manager.register('模型',{'decision-tree':DecisionTreeModel,'svm':SVMModel})judger=manager.register('评价指标',{'accuracy':AccuracyJudger(),'f1':F1ScoreJudger()})# 定义框架执行逻辑splitter=Splitter(split_ratio)train_data_test_data=splitter.split(dataset)train_data=train_data_test_data[0]test_data=train_data_test_data[1]model=Model()model.train(train_data)y_hat=model.test(test_data)judger.judge(y_hat,test_data)此时运行程序，即可通过前端页面配置具体使用哪个 python 对象作为元素，并执行定义的逻辑代码。对 python 语法的支持注意！目前本框架在定义执行逻辑时，元素仅支持函数、类、对象、原生 python 对象等，且仅对 python 的基础语法提供支持。目前框架暂不支持元组等的自动解包操作。如需要解包，请使用index代替。例如：# 不支持！train_data,test_data=splitter.split(dataset)# 请用以下代码替换train_data_test_data=splitter.split(dataset)train_data=train_data_test_data[0]test_data=train_data_test_data[1]日志模块框架提供了 logger，开发者可以方便地向前端输出文本 (print) 和图片 (imshow)。# import LoggerfromdlframeimportLogger# 注册一个名为 Test Logger 的 Loggerlogger=Logger.get_logger('Test Logger')# logger 支持打印文字logger.print('str1','str2',end='\t')# logger 支持显示图片logger.imshow(np.random.randint(0,256,(100,100,3),dtype=np.uint8))并行模块框架默认按照定义的框架执行逻辑顺序执行，您也可以通过parallel=True手动开启并行执行(TODO: 目前仅为单线程)。此时，本框架会按照定义逻辑的拓扑排序执行代码。对于拓扑排序结果相同的，不保证执行的先后顺序。例如：withWebManager(parallel=True)asmanager:clsss=manager.register_element('cls_1',{'c1':A('c1'),'c2':A('c2')})clsss.f1()clsss.f2()clsss.f3()三个函数执行顺序可能不同。如果希望按 f1, f2, f3的顺序执行，可以使用>和<指定节点顺序。例如：clsss.f1()>clsss.f2()>clsss.f3()也可指定元素运算顺序，比如：withWebManager(parallel=True)asmanager:clsss=manager.register_element('cls_1',{'c1':A('c1'),'c2':A('c2')})result1=clsss.f1()result2=clsss.f2()如果需要指定result1优先于result2得到结果，则可以指定：result1>result2变量和方法可以混用。例如：result1>clsss.f2()指定运行 ip 与端口号withWebManager(host='0.0.0.0',port=8765):pass关于前端本框架仅提供 WebSocket 服务，不提供页面显示。需配合前端使用。前端代码开源在仓库。注意！由于底层使用ws，对于某些浏览器，可能无法通过安全检查，从而导致前后端无法连接。请禁用相关安全策略后重试。其它工具PIC_Timer# example 1# function timerprint('='*50,'example 1','='*50)@PICTimerdeff1():for_inrange(100000):b=_f1()# example 2# with code blockprint('='*50,'example 2','='*50)withPICTimer.getTimer('example2')ast:for_inrange(1,100000):if_%20000==0:t.showTime()bb=_# example 3print('='*50,'example 3','='*50)timer=PICTimer.getTimer('example3')timer.startTimer()# or `timer = PICTimer.getTimer('example3', autoStart=True)`foridxinrange(3):for_inrange(1,100000):if_%20000==0:timer.showTime("stage_"+str(_))bb=_timer.forceShowTime()# you can output results before summarytimer.summary()# example 4# create sub-timerprint('='*50,'example 4','='*50)timer=PICTimer.getTimer('example4',autoStart=True)foridxinrange(3):subTimer=timer.getTimer('sub_'+str(idx),autoStart=True)for_inrange(1,100000):if_%20000==0:subTimer.showTime("stage_"+str(_))bb=_timer.showTime()timer.summary()make_recursive_func# dict argsarg1={idx:'arg1_k_'+str(idx)foridxinrange(3)}arg2={idx:'arg2_k_'+str(idx)foridxinrange(3)}# list argsarg1=[_for_inrange(10)]arg2=[_for_inrange(10)]# tuple / generator argsarg1=(_for_inrange(10))arg2=(_for_inrange(10))# non-iterable argsarg1=0arg2=1# mutiple argsarg1={idx:['arg1_k_'+str(idx)+'_l_'+str(_)for_inrange(2)]foridxinrange(3)}arg2={idx:['arg2_k_'+str(idx)+'_l_'+str(_)for_inrange(2)]foridxinrange(3)}@make_recursive_funcdeff1(x,base):returnbase.format(x)@make_recursive_funcdeff2(x,y,base):returnbase.format(x,y)@make_recursive_funcdeff3(x,y,base1,base2):returnbase1.format(x),base2.format(y)@make_multi_return_recursive_funcdeff4(x,y,base1,base2):returnbase1.format(x),base2.format(y)res1=f1(arg1,base="arg1:{}")res2=f2(arg1,arg2,base="arg1:{}, arg2:{}")res3=f3(arg1,arg2,base1="arg1:{}",base2=" arg2:{}")res4=f4(arg1,arg2,base1="arg1:{}",base2=" arg2:{}")print(res1)print(res2)print(res3)print(res4)