skulpt学习
官方文档 http://skulpt.org/
简介
Skulpt 是一个完全在浏览器中的 Python 实现。
不需要预处理、插件或服务器端支持,只需编写 Python 并重新加载。
Python 是在 Linux、Windows 或 Mac OS X 上运行,而不是在浏览器中运行!因此,为了提供真正的 Python 体验,Skulpt 必须提供一个运行时环境,编译后的代码在其中执行。此运行时环境由 skulpt.min.js 和 skulpt-stdlib.js 文件提供,您必须在网页中包含这些文件才能使 Skulpt 工作。
skulpt内置模块
abstract.js -- 包含大量抽象函数定义
biginteger.js -- 实现 Python 的长整数类型
bool.js
skulpt-stdlib.js -- 内置函数:范围、最小值、最大值等在这里定义
builtindict.js -- 提供从标准 Python 名称到 skulpt-stdlib.js 中的内部名称的映射
dict.js
enumerate.js
env.js
errors.js -- 异常在此处定义
file.js
float.js
function.js
generator.js
import.js
int.js
list.js
long.js
method.js
module.js
native.js
number.js
object.js -- 大多数东西“继承”自对象
set.js
slice.js
str.js
timsort.js
tuple.js
type.js
skulpt内置了一些常用模块(libs):
- turtle
- math
- random
- time
- 等等
也有许多模块还未实现,或者只能部分实现:
- urllib2
- md5
- 等等
如果想查看所有的内置模块情况的话可以用上面的示例代码运行后在浏览器控制台打印
Sk.builtinFiles.files
.py后缀的基本都是未实现的,.js后缀的就是已实现的模块了
<script src="skulpt.min 2.js"></script>
<script src="skulpt-stdlib 2.js"></script>
this.Sk.configure({
// 表明现在是python3
__future__: this.Sk.python3,
// 输出函数
output: self.out,
// 导入模块时调用
read: self.read,
// fileopen && filewrite函数被调用时调用
fileopen: file => {
console.log("skulpt file open ", file);
},
filewrite: file => {
console.log("skulpt file write ", file);
},
// 调用input指令时调用
inputfun: self.inputfun,
inputfunTakesPrompt: true
});
如何开发自定义第三方包?
-
第一种 修改源码
- 第二种 (目前项目中采用的)
// 第三方模块列表
var externalLibs = {
// 确保模块路径能访问到,这里我用的是相对路径
"./custom1/__init__.js": "./custom1.js",
"./custom2/__init__.js": "./custom2.js",
};
function builtinRead(file) {
console.log("Attempting file: " + Sk.ffi.remapToJs(file), 'file:', file);
// console.log('Sk.builtinFiles.files[file]:',Sk.builtinFiles.files[file], 'Sk.builtinFiles.files:',Sk.builtinFiles.files)
if (externalLibs[file] !== undefined) {
return Sk.misceval.promiseToSuspension(
fetch(externalLibs[file]).then(
function (resp) { console.log("text:",resp.text())
return resp.text(); }
));
}
if (Sk.builtinFiles === undefined || Sk.builtinFiles.files[file] === undefined) {
throw "File not found: '" + file + "'";
}
return Sk.builtinFiles.files[file];
}
Sk.configure({
inputfun: function (prompt) {
// return window.prompt(prompt);
return new Promise(function (resolve) {
document.getElementById('textarea').onkeyup = function (e) {
if (e.keyCode == 13) {
var textareavalue = document.getElementById('textarea').value;
resolve(textareavalue.replace(/\n|\r/g, ""));
let textarea = document.getElementById('textarea')
document.getElementById('textarea').after(textareavalue);
textarea.parentNode.removeChild(textarea)
}
}
})
},
inputfunTakesPrompt: true,
output: outf,
read: builtinRead
});
src/builtin/cartoon.js
src/builtin/cartoon/__init__.js
src/lib/cartoon.js
src/lib/cartoon/__init__.js
./cartoon.js
./cartoon/__init__.js
src/builtin/cartoon.py
src/builtin/cartoon/__init__.py
src/lib/cartoon.py
src/lib/cartoon/__init__.py
./cartoon.py
./cartoon/__init__.py
// 匹配这些 顺序
基础用法api
importMainWithBody (name, dumpJS, body, canSuspend)
将python转成js的方法
Sk.ffi.remapToJs
在js中将python对象转成js对象
Sk.ffi.remapToPy
maps from Javascript Object/Array/string to Python dict/list/str.
only works on basic objects that are being used as storage, doesn't handle functions, etc.
Sk.misceval.promiseToSuspension
接收一个promise实例
阻塞代码,相当于sleep函数
Sk.misceval.callsim
相当于可以在js中执行python 对象函数代码
接收俩参数,一个函数对象,一个是函数的参数
Sk.abstr.typeName(obj)
判断类型,接收一个python对象,返回数据类型
目录结构
skulpt核心代码 Sk.importMainWithBody
- importMainWithBody 这个方法真正将python转换成js的方法
let result = this.Sk.misceval.asyncToPromise(() => {
this.props.updateEditorValueByKey('runCode',true)
return this.Sk.importMainWithBody(
"<stdin>",
false,
code,
true
);
});
result
.then(mod => {
if(!this.props.runCode) return
let reacCheckRes = this.rearCheck(code,false)
console.log('成功后置代码检查',reacCheckRes);
if(reacCheckRes.passed){
// 执行成功
// if(code.indexOf("if music.key()") > -1) return
if(checkStr(code, 'music.key()')) return
this.print({type:1,text:'代码运行结束'})
this.runSuccess(code)
this.setSnapshot(code, '运行成功' , '运行成功')
}else{
this.setSnapshot(code, '结果错误', reacCheckRes.message)
this.runFail(reacCheckRes.message)
}
})
.catch(err => {
if(!this.props.runCode) return
console.log(err,'err');
let { traceback } = err;
let errMsg = err.args.v[0].v
let line = traceback.length? traceback[traceback.length-1].lineno: ''
let errStr = line?`${errMsg} on line ${line}`:''
let reacCheckRes = this.rearCheck(code,true,errStr)
console.log('失败后置代码检查',reacCheckRes);
this.runFail(reacCheckRes.message)
this.props.updateEditorValueByKey('runCode',false)
this.props.editorVm.current.editor.gotoLine(line)
this.setMarkLine(line)
this.setSnapshot(code, '运行错误', reacCheckRes.message)
}).finally(()=>{
// if(code.indexOf("if music.key()") > -1) return
if(checkStr(code, 'music.key()')) return
this.props.updateEditorValueByKey('runCode',false)
this.submitKz()
})
skulpt 源码
/**
* **Run Python Code in Skulpt**
*
* When you want to hand Skulpt a string corresponding to a Python program this is the function.
*
* @param name {string} File name to use for messages related to this run
* @param dumpJS {boolean} print out the compiled javascript
* @param body {string} Python Code
* @param canSuspend {boolean} Use Suspensions for async execution
*
*/
Sk.importMainWithBody = function (name, dumpJS, body, canSuspend) {
Sk.dateSet = false;
Sk.filesLoaded = false;
// Added to reset imports
Sk.sysmodules = new Sk.builtin.dict([]);
Sk.realsyspath = undefined;
Sk.resetCompiler();
return Sk.importModuleInternal_(name, dumpJS, "__main__", body, undefined, false, canSuspend);
};
Sk.importModuleInternal_() //这个函数被return 出来,我们看看他做了什么
Sk.importModuleInternal_(name, dumpJS, "__main__", body, undefined, false, canSuspend)
//传了7个参数