Python 和 JS 有哪些相同之处
【嵌牛导读】Python是一门运用很广泛的语言,自动化脚本、爬虫,甚至在深度学习领域也都有Python的身影。作为一名前端开发者,也了解ES6中的很多特性借鉴自Python(比如默认参数、解构赋值、Decorator等),同时本文会对Python的一些用法与JS进行类比。不管是提升自己的知识广度,还是更好地迎接AI时代,Python都是一门值得学习的语言。
【嵌牛鼻子】python与JS的相似之处
【嵌牛提问】python与JS有哪些相似呢?
【嵌牛正文】
数据类型
在Python中,最常用的能够直接处理的数据类型有以下几种:
数字[整数(int)、浮点型(float)、长整型(long)、复数(complex)]
字符串(str)
布尔值(bool)
空值(None)
除此之外,Python还提供了列表[list]、字典[dict]等多种数据类型,这在下文中会介绍。
类型转换与类型判断
与JS十分类似,python也能实现不同数据类型间的强制与隐式转换,例子如下:
强制类型转换:
int('3')#3 str(3.14)#'3.14' float('3.14')#3.14 #区别于JS只有Number一种类型,Python中数字中的不同类型也能相互强制转换 float(3)#3.0 bool(3)#True bool(0)#False
隐式类型转换:
1+1.0#2.0 1+False#1 1.0+True#2.0 #区别于JS的String+Number=String,py中str+int会报错 1+'1'#TypeError:cannotconcatenate'str'and'int'objects
此外写代码的时候经常会需要判断值的类型,可以使用python提供的type()函数获取变量的类型,或者使用isinstance(x,type)来判断x是否属于相应的type类型。
type(1.3)==float#True isinstance('a',str)#True isinstance(1.3,int)#False isinstance(True,bool)#True isinstance([],list)#True isinstance({},dict)#True
有序集合类型
集合是指包含一组元素的数据结构,有序集合即集合里面的元素是是按照顺序排列的,Python中的有序集合大概有以下几类:list,tuple,str,unicode。
list类型
Python中List类型类似于JS中的Array,
L=[1,2,3] printL[-1]#'3' L.append(4)#末尾添加元素 printL#[1,2,3,4] L.insert(0,'hi')#指定索引位置添加元素 printL#['hi',1,2,3,4] L.pop()#末尾移除元素L.pop(2)??????2??? printL#['hi',1,2,3]
tuple类型
tuple类型是另一种有序的列表,中文翻译为"元组"。tuple和list非常类似,但是,tuple一旦创建完毕,就不能修改了。
t=(1,2,3) printt[0]#1 t[0]=11#TypeError:'tuple'objectdoesnotsupportitemassignment t=(1) printt#1t的结果是整数1 t=(1,)#为了避免出现如上有歧义的单元素tuple,所以Python规定,单元素tuple要多加一个逗号"," printt#(1,)
无序集合类型
dict类型
Python中的dict类型类似于JS中的{}(最大的不同是它是没有顺序的),它有如下特点:
查找速度快(无论dict有10个元素还是10万个元素,查找速度都一样)
占用内存大(与list类型相反)
dict中的key不能重复
dict中存储的key-value序对是没有顺序的
d={ 'a':1, 'b':2, 'c':3 }
printd#{'a':1,'c':3,'b':2} 可以看出打印出的序对没有按正常的顺序打出
#遍历dict forkey,valueind.items(): print('%s:%s'%(key,value)) #a:1 #c:3 #b:2
set类型
有的时候,我们只想要dict的key,不关心key对应的value,而且要保证这个集合的元素不会重复,这时,set类型就派上用场了。set类型有如下特点:
set存储的元素和dict的key类似,必须是不变对象
set存储的元素也是没有顺序的
s=set(['A','B','C','C']) prints#set(['A','C','B']) s.add('D') prints#set(['A','C','B','D']) s.remove('D') prints#set(['A','C','B'])
Python中的迭代
在介绍完Python中的有序集合和无序集合类型后,必然存在遍历集合的for循环。但是和其它语言的标准for循环不同,Python中的所有迭代是通过for...in来完成的。以下给出一些常用的迭代demos:
索引迭代:
L=['apple','banana','orange'] forindex,nameinenumerate(L):#enumerate()函数把['apple','banana','orange']变成了类似[(0,'apple),(1,'banana'),(2,'orange')]的形式 printindex,'-',name #0-apple #1-banana #2-orange
迭代dict的value:
d={'apple':6,'banana':8,'orange':5} printd.values()#[6,8,5] forvind.values() printv #6 #8 #5
迭代dict的key和value:
d={'apple':6,'banana':8,'orange':5} forkey,valueind.items() printkey,':',value #apple:6 #banana:8 #orange:5
切片操作符
Python提供的切片操作符类似于JS提供的原生函数slice()。有了切片操作符,大大简化了一些原来得用循环的操作。
L=['apple','banana','orange','pear'] L[0:2]#['apple','banana']取前2个元素 L[:2]#['apple','banana']如果第一个索引是0,可以省略 L[:]#['apple','banana','orange','pear']只用一个:,表示从头到尾 L[::2]#['apple','orange']第三个参数表示每N个取一个,这里表示从头开始,每2个元素取出一个来
列表生成器
如果要生成[1x1,2x2,3x3,...,10x10]怎么做?方法一是循环:
L=[] forxinrange(1,11): L.append(x*x)
但是循环太繁琐,而列表生成式则可以用一行语句代替循环生成上面的list:
#把要生成的元素x*x放到前面,后面跟for循环,就可以把list创建出来
[x*xforxinrange(1,11)]
#[1,4,9,16,25,36,49,64,81,100]
列表生成式的for循环后面还可以加上if判断(类似于JS中的filter()函数),示例如下:
[x*xforxinrange(1,11)ifx%2==0]
#[4,16,36,64,100]
for循环可以嵌套,因此,在列表生成式中,也可以用多层for循环来生成列表。
[m+nformin'ABC'fornin'123']
#['A1','A2','A3','B1','B2','B3','C1','C2','C3']
Python函数
默认参数
JS中ES6的默认参数正是借鉴于Python,用法如下:
defgreet(name='World'): print'Hello,'+name+'.' greet()#Hello,World. greet('Python')#Hello,Python.
可变参数
类似于JS函数中自动识别传入参数的个数,Python也提供了定义可变参数,即在可变参数的名字前面带上个*号。
deffn(*args): printargs fn()#() fn('a')#('a',) fn('a','b')#('a','b')
Python解释器会把传入的一组参数组装成一个tuple传递给可变参数,因此,在函数内部,直接把变量args看成一个tuple就好了。
常用高阶函数
Python中常用的函数(map、reduce、filter)的作用和JS中一致,只是用法稍微不同。
map函数:接收一个函数f和一个list,并通过把函数f依次作用在list的每个元素上,得到一个新的list并返回。
deff(x): returnx*x printmap(f,[1,2,3,4,5,6,7,8,9])#[1,4,9,16,25,36,49,64,81]
reduce函数:接收一个函数f和一个list(可以接受第三个值作为初始值),reduce()对list的每个元素反复调用函数f,并返回最终结果值。
deff(x,y): returnx*y reduce(f,[1,3,5])#15
filter函数:接收一个函数f和一个list,这个函数f的作用是对每个元素进行判断,返回True或False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
defis_odd(x): returnx%2==1 filter(is_odd,[1,4,6,7,9,12,17])#[1,7,9,17]
匿名函数
和JS的匿名函数不同的地方是,Python的匿名函数中只能有一个表达式,且不能写return。拿map()函数为例:
map(lambdax:x*x,[1,2,3,4,5,6,7,8,9])#[1,4,9,16,25,36,49,64,81]
关键词lambda表示匿名函数,冒号前面的x表示函数参数,可以看出匿名函数lambdax:x*x实际上就是:
deff(x): returnx*x
闭包
之前写过一些关于JS闭包的文章,比如深入浅出JavaScript之闭包(Closure)、以及读书笔记-你不知道的JavaScript(上),Python中闭包的定义和JS中的是一致的即:内层函数引用了外层函数的变量,然后返回内层函数。下面来看下Py中闭包之for循环经典问题:
#希望一次返回3个函数,分别计算1x1,2x2,3x3: defcount(): fs=[] foriinrange(1,4): deff(): returni*i fs.append(f) returnfs f1,f2,f3=count()#这种写法相当于ES6中的解构赋值 printf1(),f2(),f3()#999
老问题了,f1(),f2(),f3()结果不应该是1,4,9吗,实际结果为什么都是9呢?
原因就是当count()函数返回了3个函数时,这3个函数所引用的变量i的值已经变成了3。由于f1、f2、f3并没有被调用,所以,此时他们并未计算i*i,当f1被调用时,i已经变为3了。
要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。代码修改如下:
方法一:可以理解为创建了一个封闭的作用域,i的值传给j之后,就和i没任何关系了。每次循环形成的闭包都存进了内存中。
defcount(): fs=[] foriinrange(1,4): deff(j): defg():#方法一 returnj*j returng r=f(i) fs.append(r) returnfs f1,f2,f3=count() printf1(),f2(),f3()#149
方法二:思路比较巧妙,用到了默认参数j在函数定义时可以获取到i的值,虽然没有用到闭包,但是和方法一有异曲同工之处。
defcount(): fs=[] foriinrange(1,4): deff(j=i):#方法二 returnj*j fs.append(f) returnfs f1,f2,f3=count() printf1(),f2(),f3()#149
decorator装饰器
ES6的语法中的decorator正是借鉴了Python的decorator。decorator本质上就是一个高阶函数,它接收一个函数作为参数,然后返回一个新函数。
那装饰器的作用在哪呢?先上一段日常项目中用ts写的网关代码:
@Post('/rider/detail')//URL路由 @log()//打印日志 @ResponseBody publicasyncgetRiderBasicInfo( @RequestBody('riderId')riderId:number, @RequestBody('cityId')cityId:number, ){ constresult=awaitthis.riderManager.findDetail(cityId,riderId) returnresult }
可以看出使用装饰器可以极大地简化代码,避免每个函数(比如日志、路由、性能检测)编写重复性代码。
回到Python上,Python提供的@语法来使用decorator,@等价于f=decorate(f)。下面来看看@log()在Python中的实现:
#我们想把调用的函数名字给打印出来 @log() deffactorial(n): returnreduce(lambdax,y:x*y,range(1,n+1)) printfactorial(10) #来看看@log()的定义 deflog(): deflog_decorator(f): deffn(x): print'调用了函数'+f.__name__+'()' returnf(x) returnfn returnlog_decorator #结果 #调用了函数factorial() #3628800 class
面向对象编程
面向对象编程是一种程序设计范式,基本思想是:用类定义抽象类型,然后根据类的定义创建出实例。在掌握其它语言的基础上,还是比较容易理解这块知识点的,比如从下面两种写法可以看出不同语言的语言特性间竟然有如此多的共性。
es6:(附:本文的主题是python,所以只是初略展示下js中类的定义以及实例的创建,为了说明写法的相似性)
classPerson{ constructor(name,age){ this.name=name this.age=age } } constchild1=newPerson('XiaoMing',10)
Python:(核心要点写在注释中)
#定义一个Person类:根据Person类就可以造成很多child实例 classPerson(object): address='Earth'#类属性(实例公有) def__init__(self,name,age):#创建实例时,__init__()方法被自动调用 self.name=name self.age=age defget_age(self):#定义实例方法,它的第一个参数永远是self,指向调用该方法的实例本身,其他参数和普通函数是一样的 returnself.age child1=Person('XiaoMing',10) child2=Person('XiaoHong',9) printchild1.name#'XiaoMing' printchild2.get_age()#9 printchild1.address#'Earth' printchild2.address#'Earth'
继承
child属于Student类,Student类属于People类,这就引出了继承:即获得了父类的方法属性后又能添加自己的方法属性。
classPerson(object): def__init__(self,name,age): self.name=name self.age=age classStudent(Person): def__init__(self,name,age,grade): super(Student,self).__init__(name,age)#这里也能写出Person.__init__(self,name,age) self.grade=grade s=Student('XiaoMing',10,90) prints.name#'XiaoMing' prints.grade#90
可以看到子类在父类的基础上又增加了grade属性。我们可以再来看看s的类型。
isinstance(s,Person) isinstance(s,Student)
可以看出,Python中在一条继承链上,一个实例可以看成它本身的类型,也可以看成它父类的类型。
总结
以上所述是小编给大家介绍的Python和JS有哪些相同之处,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!