python写文字方法_Transcrypt: 用Python写js的方法
Transcrypt是一個(gè)很有意思的工具:
它讓你告別手寫(xiě)繁復(fù)的JavaScript代碼,使用相對(duì)簡(jiǎn)明清晰的Python代替這一工作。
之后使用這個(gè)工具,可以把Python編寫(xiě)的代碼轉(zhuǎn)換成JavaScript。
1. 為什么不直接寫(xiě)JavsScript?
JavaScript本身不算是很難的編程語(yǔ)言,但還是有很多不便之處。這里只能舉幾個(gè)例子:
1.1 js的模塊化問(wèn)題。
想要實(shí)現(xiàn)一個(gè)很復(fù)雜的js程序,一般要考慮將不同的功能拆分成模塊,然后各自完成各自的任務(wù)。
然而,js本身沒(méi)有什么方式可以做到這一點(diǎn):
要么在瀏覽器或者NodeJS中,使用require這樣的方案(”AMD”—-模塊異步加載)(瀏覽器還需要額外加載require.js),
要么使用各種打包工具(CommonJS—-規(guī)定了通用的模塊定義方式),根據(jù)模塊各部分代碼相互關(guān)系,將所有的代碼打包進(jìn)一個(gè)巨大的文件。
Transcrypt支持Python的模塊機(jī)制(import語(yǔ)法),效果上最后還是生成一個(gè)打包的代碼文件,但使用起來(lái),比CommonJS要清晰一些。
1.2 缺乏對(duì)class這樣的關(guān)鍵字的支持
JavaScript雖然算是一種基于對(duì)象的語(yǔ)言—-JavaScript中包括數(shù)字、字符串等都是對(duì)象,
但又沒(méi)有辦法通過(guò)class來(lái)自己聲明一個(gè)對(duì)象。
這就導(dǎo)致不同的程序員,會(huì)采用不同的方案來(lái)構(gòu)建對(duì)象。比如有使用Object的:
var owl = {};
owl.color = "white";
owl.category = "Bubo bubo";
owl.eat = function(){ ... };
或者改寫(xiě)一個(gè)函數(shù),增加各種attributes:
function Owl(){
var self = this;
this.color = "white";
this.category = "Bubo bubo";
this.eat = function(){ ... };
return this;
}
var owl = new Owl();
1.3 缺乏語(yǔ)法糖,代碼復(fù)雜
Python簡(jiǎn)潔的語(yǔ)法,很多得益于豐富的語(yǔ)法糖:
很簡(jiǎn)潔的幾句話就可以實(shí)現(xiàn)復(fù)雜的功能,而JavaScript則可能要從頭開(kāi)始寫(xiě)一系列代碼。
舉幾個(gè)例子:
a) 使用給定的值生成一個(gè)字符串
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)
這也是一個(gè)簡(jiǎn)單的例子,如何套用模板,將數(shù)據(jù)轉(zhuǎn)換成供顯示的文本。js的解決方案就復(fù)雜許多:
首先,js是不支持帶有換行的字符串變量的。所以我們不能用Python"""..."""這種語(yǔ)法,指定一個(gè)帶有換行的字符串。
其次,也不能在js的字符串中定義占位符,然后用數(shù)據(jù)填充,所以要自行斷開(kāi)字符串,將數(shù)據(jù)與字符串合并。
看起來(lái)結(jié)果就是:
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);
即使看上去代碼量差不多,這樣做還是有一個(gè)缺點(diǎn):
如果需要修改模板,使用Python,只要將帶有占位符的字符串換掉就可以了(比如字符串在單獨(dú)的模板文件中予以定義),
但使用js,就需要具體修改帶有邏輯運(yùn)算符的代碼。這樣就很不直觀,容易出錯(cuò)。
b) 根據(jù)已有數(shù)據(jù)生成一個(gè)新的數(shù)組
假設(shè)我們有一個(gè)數(shù)組[-2, -1, 0, 1, 2, 3, 4],想列出這個(gè)數(shù)組中大于0的各個(gè)數(shù)字的平方。
使用js的思路,是新建一個(gè)數(shù)組,然后遍歷原數(shù)組,檢查各項(xiàng)是否大于0, 如果是,將結(jié)果記錄到新的數(shù)組:
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則簡(jiǎn)單很多。Python支持在構(gòu)建list的時(shí)候,指定條件,并使用表達(dá)式指定要放入list的值:
original = [-2, -1, 0, 1, 2, 3, 4]
result = [each ** 2 for each in original if each > 0]
1.4 復(fù)雜的異步編程
JavaScript的另一個(gè)令人詬病的問(wèn)題,是在調(diào)用一系列異步調(diào)用時(shí)難以組織代碼。
實(shí)際應(yīng)用中,無(wú)論NodeJS還是瀏覽器,都要遇到各種異步調(diào)用的代碼。
假設(shè)我們有3個(gè)函數(shù):
readFile用于讀取一個(gè)文件;
encrypt用于加密數(shù)據(jù);
upload用于將數(shù)據(jù)上傳到服務(wù)器。
這三個(gè)函數(shù)都是異步調(diào)用的。
傳統(tǒng)的方式,一般是在實(shí)際完成功能需要的參數(shù)之外,這些函數(shù)還接受一個(gè)callback(回調(diào)函數(shù))作為輸入。
這樣調(diào)用上述函數(shù)之后,他們會(huì)立刻返回,并不耽誤時(shí)間。然后當(dāng)函數(shù)對(duì)應(yīng)的后臺(tái)任務(wù)完成時(shí),再呼叫callback,傳入結(jié)果。
比如這樣看,可以假設(shè)readFile的用法是readFile(filename, callback)。
這個(gè)函數(shù)接受一個(gè)filename作為要讀取的文件名,然后在讀取完畢時(shí)呼叫callback函數(shù),傳入讀取結(jié)果。
實(shí)際調(diào)用時(shí),要寫(xiě)成:
readFile("/path/to/somefile", function(err, data){
if(err){
...
return; // 如果讀取文件出錯(cuò)
}
// 否則讀取文件成功,繼續(xù)做下一步的事情
});
假如我們想在讀取文件后,將文件內(nèi)容加密,就要在上述代碼的讀取成功處,
加上對(duì)encrypt=encrypt(data, callback)函數(shù)的調(diào)用。于是代碼就成了這個(gè)樣子:
readFile("/path/to/somefile", function(err, data){
if(err){
...
return; // 如果讀取文件出錯(cuò)
}
// 讀取文件成功,加密data
encrypt(data, function(err, ciphertext){
if(err){
...
return; // 加密失敗
}
// 加密文件成功,繼續(xù)做別的事情
});
});
如果進(jìn)一步,想在加密之后,將密文上傳到服務(wù)器,整個(gè)代碼就……
readFile("/path/to/somefile", function(err, data){
if(err){
...
return; // 如果讀取文件出錯(cuò)
}
// 讀取文件成功,加密data
encrypt(data, function(err, ciphertext){
if(err){
...
return; // 加密失敗
}
// 加密文件成功,密文是ciphertext,將它上傳
upload(ciphertext, function(err, result){
if(err){
...
return; // 上傳失敗
}
// 上傳成功
});
});
});
很多時(shí)候,要完成的工作都是上面這樣一連串的。
js的回調(diào)機(jī)制,就很容易引入如上所示不斷嵌套的代碼,讓結(jié)果變得十分難看,所謂的回調(diào)地獄。
為了解決這個(gè)問(wèn)題,JavaScript引入了Promise機(jī)制。
這樣每個(gè)函數(shù)就都返回一個(gè)Promise對(duì)象。
Promise對(duì)象支持使用.then()這樣的方法,將流程串聯(lián)起來(lái):
readFile("/path/to/somefile")
.then(encrypt)
.then(upload)
.catch(function(err){
...
// 如果上面某一步出錯(cuò)的話,就直接跳到這里
});
這樣簡(jiǎn)明了許多。
Transcrypt在Promise機(jī)制的基礎(chǔ)上,結(jié)合了Python 3引入的async和await語(yǔ)法,讓上面的過(guò)程變得更加直觀:
async def encryptFileAndUpload(path):
try:
data = await readFile(path)
ciphertext = await encrypt(data)
await upload(ciphertext)
except:
# 處理錯(cuò)誤encryptFileAndUpload("/path/to/somefile")
使用await,這些異步的調(diào)用又可以寫(xiě)成一系列按順序完成的代碼,而不失對(duì)各步的控制,思路清晰很多。
2. 如何使用Transcrypt?
2.1 安裝和調(diào)用
Transcrypt可以通過(guò)pip安裝:
$ sudo pip install transcrypt
安裝后,直接在命令行調(diào)用就可以了,例如,
$ transcrypt main.py
可以將main.py轉(zhuǎn)換成js文件。
類(lèi)似Python 3在執(zhí)行代碼前會(huì)在__pycache__目錄中放置Python字節(jié)碼那樣,
transcrypt會(huì)將轉(zhuǎn)換后的文件放到相應(yīng)的__javascript__目錄。
如果要求轉(zhuǎn)換的是main.py,則在__javascript__/中,一般會(huì)有如下文件:
main.mod.js,這是僅僅包含main.py各行代碼相應(yīng)js轉(zhuǎn)譯的文件。
這個(gè)文件中會(huì)用很多transcrypt的函數(shù)“包裝”輸入的Python代碼,但基本上是一對(duì)一的對(duì)照,
因此可供用戶(hù)檢查代碼是否有問(wèn)題等。
main.js,這是將main.py轉(zhuǎn)譯為js,并嵌入transcrypt本身需要的js代碼,打包而成的文件。
這個(gè)文件可以獨(dú)立嵌入到網(wǎng)頁(yè)了。
main.min.js。如果見(jiàn)到這個(gè)文件,說(shuō)明transcrypt還進(jìn)行了代碼壓縮,這個(gè)文件應(yīng)該也可以單獨(dú)運(yùn)行。
代碼壓縮(minify)需要很多運(yùn)算,耗費(fèi)時(shí)間,在開(kāi)發(fā)程序時(shí)不方便??梢允褂?n參數(shù),跳過(guò)這一步:
$ transcrypt -n main.py
這樣就可以只生成main.js。
2.2 一些坑
Python和Javascript畢竟是兩種語(yǔ)言,雖然transcrypt可以在很大程度上將前者翻譯為后者,
但有些兩種語(yǔ)言?xún)?nèi)在的不一致,決定了編程時(shí)還需要注意許多坑。
在Transcrypt官網(wǎng)的文檔中,詳細(xì)列明了各種坑和其理由。一定要仔細(xì)閱讀。
2.2.1 類(lèi)的繼承,方法的重載
在Python中,定義基類(lèi)和子類(lèi),是很方便的事情,有時(shí)候這種編程方式會(huì)節(jié)約大量時(shí)間。
在transcrypt中,可以使用類(lèi)的繼承,但必須在轉(zhuǎn)譯時(shí),于命令行使用-e6選項(xiàng)。
這樣生成的代碼為ECMAScript 6代碼,才可以啟用這樣的諸多功能。
重載Python的類(lèi),自定義諸如__str__,__getattr__或__setattr__這樣的方法,
可以編寫(xiě)出非常簡(jiǎn)明的程序。例如一個(gè)模板程序:
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!
這個(gè)程序定義的Template類(lèi),只需要像操作一般的類(lèi)那樣給它的屬性賦值,
然后用str函數(shù)令其生成文本即可。這種用法非常直觀,但也必須在啟用了ECMAScript 6轉(zhuǎn)譯后才能利用。
2.2.2 特殊的方法名稱(chēng)
如果要在python中調(diào)用一個(gè)js模塊(比如jQuery的$.get)的get方法,直接調(diào)用會(huì)出現(xiàn)錯(cuò)誤。
根據(jù)transcrypt文檔的解釋,這是因?yàn)樵趐ython中,get本身具有特定的用途,
故須使用py_get與js_get區(qū)別調(diào)用python內(nèi)部和原生js的get方法。
同理,對(duì)于set方法也有類(lèi)似的規(guī)定。
2.2.3 __pragma__: 很多特性的開(kāi)關(guān)
transcrypt提供了一個(gè)__pragma__函數(shù),可以在程序中微調(diào)轉(zhuǎn)譯時(shí)的行為。
例如,要在python代碼中調(diào)用jQuery,不能直接使用$變量,因?yàn)?并不是一個(gè)規(guī)范的Python變量名。
這時(shí),就要用__pragma__為$定義一個(gè)別名:
__pragma__("alias", "S", "$")
之后,就可以在程序中用S代替$來(lái)調(diào)用jQuery了。
__pragma__能進(jìn)行的調(diào)節(jié)有許多。
很多情況下,Python本身允許的特性,transcrypt出于效率考慮默認(rèn)不支持,便需要通過(guò)這一函數(shù)啟用。請(qǐng)讀者務(wù)必參考文檔。
總結(jié)
以上是生活随笔為你收集整理的python写文字方法_Transcrypt: 用Python写js的方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 基于VHDL的vivado2017.4使
- 下一篇: python中字典数据的特点_Pytho