当前位置: 首页 > 后端技术 > Node.js

NodeJs与python的使用对比

时间:2023-04-03 15:45:59 Node.js

写这篇文章的目的是记录NodeJs(以下简称node)与python的使用对比。希望大家看完之后,对node和python有一个基本的了解。(本文使用的node版本为v12.14.0,python为v3.8.3。)简介Node是一个基于ChromeV8引擎的JavaScript(简称js)运行时。简单的说就是js代码被v8引擎(用c++写的)解释执行,然后就可以在服务端运行了。Python是一种面向对象的解释型编程语言。目前使用最广泛的python解释器是CPython,它通过C语言将python代码编译成字节码,然后在虚拟机上运行。Node适用于打包发布前端代码,服务端开发,桌面端应用开发。Python适用于科学计算、数据分析、自动化运维等场景。数据结构节点的数组对应python列表,可以存储很多不同类型的数据。节点对象对应python字典,都是key-value的形式。集合结构也是一个类似的概念,就是没有重复元素的集合。Node在python中没有元组类型,但是用Object.freeze可以达到类似的效果。nodeletlist=[1,2,3]list.push(4)//列表[1,2,3,4]list.splice(2,1)//列表[1,2,4]list.concat([5,6])//[1,2,4,5,6]list.slice(1)//[2,4]let[a,b,c]=list//a=1b=2c=4lettuple=[1,2]Object.freeze(tuple)tuple[0]=3//tuple[1,2]//一般可以使用for,forEach,for...of来遍历list。forEach((item)=>{console.log(item)})//124pythonlist=[1,2,3]list.append(4)#list[1,2,3,4]dellist[2]#列表[1,2,4]list+[5,6]#[1,2,4,5,6]list[1:]#[2,4]a,b,c=列表#a=1b=2c=4tuple=(1,2)tuple[0]=3#报错tuple(1,2)#遍历forinforiteminlist:print(item)#124变量和全局作用域在nodenode变量上定义了全局对象,可以跨多个模块访问。可以通过var、let和const访问模块中声明的变量。let和const不能在代码块(if、for等)中被外部方法访问,但var可以。除了块级作用域,还有函数作用域。函数作用域内的变量如果想在函数外访问,需要通过闭包。另外,每个js文件都是一个模块,模块最终会被一个匿名函数包裹起来(exports和module是匿名函数中的参数),所以模块中的变量也是局部变量。//代码块内的变量不能在代码块外访问{leta=1constPI=3.14//const用于定义常量}console.log(a,PI)//代码块内的变量不能访问,会报错//通过闭包函数访问函数内部的变量wrap(){letn=0functioninside(){n=n+1returnn}returninside}letcount=wrap()count()//1count()//2pythonpython没有node那样的全局对象,多个模块想要共享一个变量只能通过导入同一个模块来获取共享变量。python变量定义可以直接赋值:value=1。python中只有模块、类、函数会引入新的作用域,代码块不会引入新的作用域。python的闭包和node的闭包明显不同。假设里面的函数在函数wrap里面,里面的函数想通过nonlocal关键字修改函数wrap的变量,而node可以直接使用函数wrap的变量。#存储全局变量的globalValue.py模块global_list=[]#p1.pyfrompy2import*importglobalValueif__name__=='__main__':#表示如果主条目是p1.py文件do_something()print('py1.py')print(globalVal.global_list)#p2.pyimportglobalValdefdo_something():globalVal.global_list.append('a')print('py2.py')print(globalVal.global_list)#---------------------------------defwrap():n=0definside():nonlocaln#需要使用nonlocal关键字n=n+1returnnreturninsidecount=wrap()count()#1count()#2个模块节点通过require方法导入模块。导出模块可以使用exports和module.exports,requirefinally使用module.exports对象。需要注意的是,虽然exports和module.exports使用的是同一个内存地址,但是如果exports被赋值为引用类型的值,那么相当于exports使用了一个新的内存地址,使用require方法是无法获取到exports的价值。包(package)在文件夹中用package.json表示,package.json中包含包的描述信息、依赖、运行命令等。//a.js和main.js在同一个目录exports=functionname_a(){console.log(1)}//main.jsleta=require('./a')console.log(a)//output{}如果改成module.exports,会输出[Function:name_a]python导入模块是通过import或者frompackage_nameimportmodule_name导入的。模块导入也分为绝对导入和相对导入。绝对导入需要使用导入模块的完整路径。不需要相对导入。导出模块不需??要特定的语法,可以通过dir方法查看模块的变量。Python使用__init__.py文件表明当前目录是一个包。当有外部导入时,执行里面的函数(pyton3.3之后,不需要添加__init__.py文件)。__init__.py可以修改模块的导入方式。#Absoluteimportfrompackage.moduleimportfunction#Relativeimportfrom.importmodule#查看当前模块包含的变量dir()#__init__.pyfrompackage.moduleimportfunction#Function()可以在导入的模块中使用。__all__=['module']#导入一个模块,使用frompackageimport*直接使用模块中的变量和方法。性能性能方面,python比node差很多,CPython不说,带JIT的pypy也比node慢(用pypy3计算斐波那契数列,当n=40时,比node慢1秒左右)。另外,大家一般都想通过开启多线程来提高多核CPU的利用率,但是由于CPython的GIL(GlobalInterpreterLock),一个CPU一次只能执行一个线程,所以在计算密集型任务中启用多进程优化。node的worker_threads模块没有这个问题。functionfib(n){if(n===0){return0}elseif(n===1){return1}else{returnfib(n-1)+fib(n-2)}}控制台.time('fib')fib(40)console.timeEnd('fib')//python也是采用递归的方式,代码省略,大家可以在自己的电脑上试试。综上所述,node和python都在各自的领域取得了不错的进展。对于node来说,reactvue的前端封装构建和同构应用是很难被替代的(使用js的好处)。而如果Deno在性能上并不比node高出多少,那么取代node的可能性不大。语言的生态非常重要。Python具有良好的开发效率和强大的库生态;而随着近几年机器学习的热潮,python这门语言的热度一直保持在前几名。