当前位置: 首页 > 工具软件 > Transcrypt > 使用案例 >

python写文字方法_Transcrypt: 用Python写js的方法

羿经武
2023-12-01

Transcrypt是一个很有意思的工具:

它让你告别手写繁复的JavaScript代码,使用相对简明清晰的Python代替这一工作。

之后使用这个工具,可以把Python编写的代码转换成JavaScript。

1. 为什么不直接写JavsScript?

JavaScript本身不算是很难的编程语言,但还是有很多不便之处。这里只能举几个例子:

1.1 js的模块化问题。

想要实现一个很复杂的js程序,一般要考虑将不同的功能拆分成模块,然后各自完成各自的任务。

然而,js本身没有什么方式可以做到这一点:

要么在浏览器或者NodeJS中,使用require这样的方案(”AMD”—-模块异步加载)(浏览器还需要额外加载require.js),

要么使用各种打包工具(CommonJS—-规定了通用的模块定义方式),根据模块各部分代码相互关系,将所有的代码打包进一个巨大的文件。

Transcrypt支持Python的模块机制(import语法),效果上最后还是生成一个打包的代码文件,但使用起来,比CommonJS要清晰一些。

1.2 缺乏对class这样的关键字的支持

JavaScript虽然算是一种基于对象的语言—-JavaScript中包括数字、字符串等都是对象,

但又没有办法通过class来自己声明一个对象。

这就导致不同的程序员,会采用不同的方案来构建对象。比如有使用Object的:

var owl = {};

owl.color = "white";

owl.category = "Bubo bubo";

owl.eat = function(){ ... };

或者改写一个函数,增加各种attributes:

function Owl(){

var self = this;

this.color = "white";

this.category = "Bubo bubo";

this.eat = function(){ ... };

return this;

}

var owl = new Owl();

1.3 缺乏语法糖,代码复杂

Python简洁的语法,很多得益于丰富的语法糖:

很简洁的几句话就可以实现复杂的功能,而JavaScript则可能要从头开始写一系列代码。

举几个例子:

a) 使用给定的值生成一个字符串

output = """My name is {name}, I'm {age} years old.

My favourite fruit is {favourite}.""".format({

"favourite": "banana",

"name": "Alice",

"age": 18,

})

console.log(output)

这也是一个简单的例子,如何套用模板,将数据转换成供显示的文本。js的解决方案就复杂许多:

首先,js是不支持带有换行的字符串变量的。所以我们不能用Python"""..."""这种语法,指定一个带有换行的字符串。

其次,也不能在js的字符串中定义占位符,然后用数据填充,所以要自行断开字符串,将数据与字符串合并。

看起来结果就是:

var data = {

"favourite": "banana",

"name": "Alice",

"age": 18,

};

var output = "My name is" + data.name + ", I'm" + data.age + "years old.\n";

output += "My favourite fruit is" + data.favourite + ".";

console.log(output);

即使看上去代码量差不多,这样做还是有一个缺点:

如果需要修改模板,使用Python,只要将带有占位符的字符串换掉就可以了(比如字符串在单独的模板文件中予以定义),

但使用js,就需要具体修改带有逻辑运算符的代码。这样就很不直观,容易出错。

b) 根据已有数据生成一个新的数组

假设我们有一个数组[-2, -1, 0, 1, 2, 3, 4],想列出这个数组中大于0的各个数字的平方。

使用js的思路,是新建一个数组,然后遍历原数组,检查各项是否大于0, 如果是,将结果记录到新的数组:

var original = [-2, -1, 0, 1, 2, 3, 4];

var result = [];

for(var i=0; i

if(original[i] > 0){

result.push(Math.pow(original[i], 2));

}

}

Python则简单很多。Python支持在构建list的时候,指定条件,并使用表达式指定要放入list的值:

original = [-2, -1, 0, 1, 2, 3, 4]

result = [each ** 2 for each in original if each > 0]

1.4 复杂的异步编程

JavaScript的另一个令人诟病的问题,是在调用一系列异步调用时难以组织代码。

实际应用中,无论NodeJS还是浏览器,都要遇到各种异步调用的代码。

假设我们有3个函数:

readFile用于读取一个文件;

encrypt用于加密数据;

upload用于将数据上传到服务器。

这三个函数都是异步调用的。

传统的方式,一般是在实际完成功能需要的参数之外,这些函数还接受一个callback(回调函数)作为输入。

这样调用上述函数之后,他们会立刻返回,并不耽误时间。然后当函数对应的后台任务完成时,再呼叫callback,传入结果。

比如这样看,可以假设readFile的用法是readFile(filename, callback)。

这个函数接受一个filename作为要读取的文件名,然后在读取完毕时呼叫callback函数,传入读取结果。

实际调用时,要写成:

readFile("/path/to/somefile", function(err, data){

if(err){

...

return; // 如果读取文件出错

}

// 否则读取文件成功,继续做下一步的事情

});

假如我们想在读取文件后,将文件内容加密,就要在上述代码的读取成功处,

加上对encrypt=encrypt(data, callback)函数的调用。于是代码就成了这个样子:

readFile("/path/to/somefile", function(err, data){

if(err){

...

return; // 如果读取文件出错

}

// 读取文件成功,加密data

encrypt(data, function(err, ciphertext){

if(err){

...

return; // 加密失败

}

// 加密文件成功,继续做别的事情

});

});

如果进一步,想在加密之后,将密文上传到服务器,整个代码就……

readFile("/path/to/somefile", function(err, data){

if(err){

...

return; // 如果读取文件出错

}

// 读取文件成功,加密data

encrypt(data, function(err, ciphertext){

if(err){

...

return; // 加密失败

}

// 加密文件成功,密文是ciphertext,将它上传

upload(ciphertext, function(err, result){

if(err){

...

return; // 上传失败

}

// 上传成功

});

});

});

很多时候,要完成的工作都是上面这样一连串的。

js的回调机制,就很容易引入如上所示不断嵌套的代码,让结果变得十分难看,所谓的回调地狱。

为了解决这个问题,JavaScript引入了Promise机制。

这样每个函数就都返回一个Promise对象。

Promise对象支持使用.then()这样的方法,将流程串联起来:

readFile("/path/to/somefile")

.then(encrypt)

.then(upload)

.catch(function(err){

...

// 如果上面某一步出错的话,就直接跳到这里

});

这样简明了许多。

Transcrypt在Promise机制的基础上,结合了Python 3引入的async和await语法,让上面的过程变得更加直观:

async def encryptFileAndUpload(path):

try:

data = await readFile(path)

ciphertext = await encrypt(data)

await upload(ciphertext)

except:

# 处理错误encryptFileAndUpload("/path/to/somefile")

使用await,这些异步的调用又可以写成一系列按顺序完成的代码,而不失对各步的控制,思路清晰很多。

2. 如何使用Transcrypt?

2.1 安装和调用

Transcrypt可以通过pip安装:

$ sudo pip install transcrypt

安装后,直接在命令行调用就可以了,例如,

$ transcrypt main.py

可以将main.py转换成js文件。

类似Python 3在执行代码前会在__pycache__目录中放置Python字节码那样,

transcrypt会将转换后的文件放到相应的__javascript__目录。

如果要求转换的是main.py,则在__javascript__/中,一般会有如下文件:

main.mod.js,这是仅仅包含main.py各行代码相应js转译的文件。

这个文件中会用很多transcrypt的函数“包装”输入的Python代码,但基本上是一对一的对照,

因此可供用户检查代码是否有问题等。

main.js,这是将main.py转译为js,并嵌入transcrypt本身需要的js代码,打包而成的文件。

这个文件可以独立嵌入到网页了。

main.min.js。如果见到这个文件,说明transcrypt还进行了代码压缩,这个文件应该也可以单独运行。

代码压缩(minify)需要很多运算,耗费时间,在开发程序时不方便。可以使用-n参数,跳过这一步:

$ transcrypt -n main.py

这样就可以只生成main.js。

2.2 一些坑

Python和Javascript毕竟是两种语言,虽然transcrypt可以在很大程度上将前者翻译为后者,

但有些两种语言内在的不一致,决定了编程时还需要注意许多坑。

在Transcrypt官网的文档中,详细列明了各种坑和其理由。一定要仔细阅读。

2.2.1 类的继承,方法的重载

在Python中,定义基类和子类,是很方便的事情,有时候这种编程方式会节约大量时间。

在transcrypt中,可以使用类的继承,但必须在转译时,于命令行使用-e6选项。

这样生成的代码为ECMAScript 6代码,才可以启用这样的诸多功能。

重载Python的类,自定义诸如__str__,__getattr__或__setattr__这样的方法,

可以编写出非常简明的程序。例如一个模板程序:

class Template:

def __init__(self):

self.__kv = {}

def __str__(self):

return """Welcome to {sitename}!""".format(self.__kv)

def __setattr__(self, key, value):

self.__kv[key] = value

t = Template()

t.sitename = "NeoAtlantis"

print(str(t)) # 输出 Welcome to NeoAtlantis!

这个程序定义的Template类,只需要像操作一般的类那样给它的属性赋值,

然后用str函数令其生成文本即可。这种用法非常直观,但也必须在启用了ECMAScript 6转译后才能利用。

2.2.2 特殊的方法名称

如果要在python中调用一个js模块(比如jQuery的$.get)的get方法,直接调用会出现错误。

根据transcrypt文档的解释,这是因为在python中,get本身具有特定的用途,

故须使用py_get与js_get区别调用python内部和原生js的get方法。

同理,对于set方法也有类似的规定。

2.2.3 __pragma__: 很多特性的开关

transcrypt提供了一个__pragma__函数,可以在程序中微调转译时的行为。

例如,要在python代码中调用jQuery,不能直接使用$变量,因为$并不是一个规范的Python变量名。

这时,就要用__pragma__为$定义一个别名:

__pragma__("alias", "S", "$")

之后,就可以在程序中用S代替$来调用jQuery了。

__pragma__能进行的调节有许多。

很多情况下,Python本身允许的特性,transcrypt出于效率考虑默认不支持,便需要通过这一函数启用。请读者务必参考文档。

 类似资料: