Python语言简洁,优雅,扩展性强...... 这些特点常被Python程序员挂在嘴边,确实也都是Python的特点。
要讨论语言的特点或特性,可以得到很多不同的结论,有针对语言整体而言的特性,也有针对某一个应用领域的特性。本文只从语言设计方面(其他的不讨论),总结Python的几点语言特性。
一、解释型语言
高级语言不能直接被计算机理解(计算机只能理解机器语言,二进制代码),要先将高级语言翻译成机器语言,计算机才能执行高级语言编写的代码。根据翻译工具(解释器或编译器)的不同,高级语言分为解释型语言和编译型语言。
Python是解释型语言,所以Python代码不需要编译,编写完就可以直接运行。
解释型语言相当于实时翻译,省去了编译这个步骤。每运行一次代码,解释器都要重新翻译代码,而解释器把代码翻译成机器语言是要花时间的,所以,解释型语言的运行效率比编译型语言低很多,速度慢,性能上处于劣势。
编译型语言相当于提前翻译,运行时直接运行可执行文件。编译只需要一次,后面不管运行多少次,都可以直接运行可执行文件,所以,编译型语言的运行效率比解释型语言高很多,速度快,性能上有优势。
因为性能上的劣势,解释型语言不适合开发操作系统、大型应用程序、数据库系统等对性能要求高的程序,这些程序基本都是使用编译型语言。当然,解释型语言可以通过对解释器进行优化来提高运行效率,同时,随着计算机硬件的性能提升,也可以弥补解释型语言在性能上的不足,使性能差距对生产的影响降低,甚至消除。
另一方面,因为在运行时才解释代码,解释型语言的跨平台性更好,代码移植到不同的操作系统中后可以直接运行。而因为不同操作系统识别的机器语言有差异,编译型语言移植到不同的操作系统后,需要重新编译后才能运行,跨平台性不如解释型语言。
说回Python,Python程序运行后也可以将运行的机器语言保存到以.pyc为扩展名的文件中,下次运行时,如果代码没有变化,解释器可以直接运行.pyc文件。这算是Python对运行效率的一种优化,所以,也有人说Python是一种解释型和编译型相结合的语言。
二、动态类型语言
在不同的高级语言中,都有很多数据类型,这些数据类型的定义大同小异。在代码中,数据一般保存在变量之中(被变量引用),通常会先定义变量,然后将数据赋值给变量。根据定义变量前是否需要提前声明变量的数据类型,高级语言分为动态类型语言和静态类型语言。
Python是动态类型语言,所以Python代码中不需要提前声明变量的数据类型,运行代码的时候再动态确认数据类型。
var = 100
print(var, type(var))
var = '!@#$%'
print(var, type(var))
100 <class 'int'>
!@#$% <class 'str'>
看上面的例子,定义变量var的时候赋值为100,运行时的数据类型为int(整数),再将它赋值为字符!@#$%,运行时的数据类型为str(字符串)。不仅变量的数据类型不需要提前声明,在运行过程中,数据类型还会根据不同的引用而改变。
动态类型语言不需要提前声明变量的数据类型,使代码更加简洁,可以少写很多代码,同时,也给了程序员很大的自由度,写代码时多了很多自由发挥的空间。但是,太自由了也可能会有弊端,如果一些变量定义得不规范(如多处出现同名变量名),会使代码的可读性降低,增加定位问题的难度,甚至带来一些不易察觉的BUG。
静态类型语言的每个变量都先声明了数据类型,每个变量都必须先声明才能使用,一旦声明后数据类型不能修改,这充分保证了同一个变量名在上下文中的一致性,即使代码量很大的情况下也不会出现混乱。只是,会使代码量变多,实现相同的功能,代码量会增加很多。
三、强类型语言
在高级语言中,将不同类型的变量进行运算时,有些语言可以自动对数据类型进行转换,使不同数据类型的变量能兼容,能返回运算结果,程序不报错,另一些语言必须先将数据类型转换成一致,才能进行运算,否则程序会报错。所以高级语言可以分为强类型语言和弱类型语言。
Python是强类型语言,所以Python代码中不同类型的数据运算会报错。
强类型和弱类型是体现在数据运算时不同类型的数据能否兼容,而动态类型和静态类型是体现在定义变量时是否需要先声明数据类型,所以这是两个维度的概念,不能混淆了。
a = 100
print(a, type(a))
b = '100'
print(b, type(b))
print(a + b)
100 <class 'int'>
100 <class 'str'>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
print(str(a) + b, type(str(a) + b))
print(a + int(b), type(a + int(b)))
100100 <class 'str'>
200 <class 'int'>
看上面的例子,变量a是int(整型),变量b是str(字符串),将两者相加时,会报错TypeError:不支持整型与字符串相加。当将a和b的数据类型转换成一致后,可以正常运算。
强类型语言不支持不同类型的数据直接进行运算,必须先对数据类型进行转换,这可以帮助程序员在变量运算前确认和厘清数据的类型,避免了不同数据类型进行运算的混乱。但是,不同类型的数据进行运算前,要先进行类型转化,多了一个步骤,也会降低运行效率。
弱类型语言支持不同类型的数据直接进行运算,在不同类型的数据进行运算时会自动进行转换,省了自动转换的步骤。但是,两个不同类型的数据直接运算,可能会使程序员错误判断结果的数据类型,甚至可能会带来BUG。
在动态类型和静态类型方面,Python给程序员留了足够的自由,但在强类型和弱类型方面,Python又对数据的运算进行了限制。可以猜想,Guido这么设计是经过深思熟虑的,在定义变量的时候给了足够自由,也提升了代码的简洁性,但在进行数据运算时进行了限制,加了一道保险,避免太过自由带来一些不必要的问题。
四、面向对象语言
在编程时,一个功能可以分成多个步骤来逐步实现,基本所有语言都支持按步骤实现功能和抽取可重用的函数,而面向对象语言还支持由数据和功能组合而成的对象来实现功能。所以,根据是否支持面向对象编程,高级语言可以分为面向对象语言和面向过程语言。
Python是面向对象语言,Python中一切皆对象,可以将数据和功能封装到对象中,从对象的角度去处理问题和实现功能。当然,用Python也可以实现面向过程编程。
面向对象语言的设计聚焦于对象之上,将数据作为属性封装在对象内,将功能作为方法封装在对象内,不管是使用属性还是方法,都可以通过对象调用。面向对象语言具有封装、继承和多肽三大特性,可以使程序设计得更加清晰,由此也产生了很多设计模式。在复杂的业务中,不同的对象执行不同的功能,降低了代码的耦合度,有利于提高开发效率,降低重构代码的难度。
面向过程语言的代码按照业务逻辑自上而下,逐步实现功能,如果有可以重复使用的功能,可以抽取成函数。面向过程编程没有面向对象编程抽象,所以更容易理解,代码与业务逻辑环环相扣,一步一步地实现,这就使得代码的耦合度很高。即使将重复代码抽取成函数,还是很难避免代码的冗余,代码的设计模式也比较少,设计思路没有面向对象的清晰,重构代码也更难。
关于面向对象语言和面向过程语言的讨论内容很多,对于业务逻辑比较复杂的程序,比较统一的看法是面向对象优于面向过程,而对于业务逻辑简单的程序,面向对象和面向过程都可以。
上面总结了几点Python的语言特性,如果有一些编程经验,大家都会有自己的理解,每个人的理解可能会存在一些小差异,所以没必要在意是否权威,自己思考最重要。
如果对Python编程感兴趣,欢迎点击关注公众号“Python碎片”,号主会不定期分享Python相关知识。