目录
前言
前面的博文从记录了如何Setup Python开发环境,到IPython的基本使用。现在便由浅入深的学习Python编程艺术。学习一门编程语言,首先要了解其底层的实现机制和程序处理的过程,也就是了解其设计思想和解析实现。当然,初始一门语言,可以无须太过深入的去研究这些,但也要在心中建立起一个Python的知识框架,在接下来的学习过程中,不断的其填充和完善这一框架,有如造房筑楼。
初识Python
Python 支持OOP(Object Oriented Programming面向对象编程实现),是一种解析型语言,有别于编译型语言。我们对比其他不同类型的语言和两种主流的程序设计思想来理解Python的OOP和解析型的特性。
解析型与编译型
编译型语言:如C/C++,在运行前有一个独立的编译过程,会将其编译成二进制机器语言的执行文件(.exe),以后的运行无需再次编译,效率较高。特点在于,一次编译多次运行,快速的执行程序,但是也因为没有虚拟机的中间件,只能编译成符合本机指令集的可执行文件,所以不能支持跨平台。而且其在编译时既可以发现存在的语法、数据类型转换、变量类型匹配等错误,尤其会有明确的数据类型检测,因此也被归为强类型语言。
解析型语言:如Java/Python,在每次运行时都会将源代码转换成字节码(bytecode)文件(.pyc/.javac)而非二进制的机器语言。然后在将字节码交由虚拟机(jvm/pvm)处理,进而在虚拟机中根据平台的不同编译出兼容当前平台指令集的机器码。这也是Java和Python 能具有跨平台优势的根本实现,但相对的,程序执行效率也会因此而降低。而且解析型语言中的代码错误,只有在运行的时候才会Output出来,之后再对代码作出修正。这样也会造成不断运行->ERROR->修改->运行的不便,因此一般的解析型语言会配有Shell的功能,可以方便程序或代码行的调试。这也是博猪将IPython的介绍置于本篇之前的原因,学习好IPython对Python 程序的编写如虎添翼。
脚本语言:如ASP/PHP/Javascript,则是需要相应的脚本引擎来支持解析和执行。
OOP与POP
OOP、POP是两种主流的程序设计思想,各有千秋,能与契合度高的编程语言配合编写出在不同的执行平台和环境中均能发挥出最好性能的应用程序。编程思想的发展转变以计算机硬件发展为主要导向之一,从来都是时间和空间的较量。从最初硬件资源缺乏而诞生以时间换空间的POP,到现在硬件资源过剩而改进的以空间换时间,甚至满足更复杂需求的OOP。但退一步来说,并不是意味POP就逊色于OOP,谁优谁劣,只在于摆放的位置而已。在理解OOP和POP之前,首先我们对面向对象和面向过程要有一个了解,并不要将面向对象和OOP划上等号。总而言之,程序编写的修行,从来都是以编程思维和程序结构设计的研习为重中之重。
面向过程:以过程、步骤为中心。是一种步进、流程化且注重顺序的思考方式。分析为了解决问题所要执行步骤,编写函数来实现这些步骤,最后程序执行时再一个一个调用函数来最终解决问题。而POP就是基于这种思维发展而来的“面向对象的编程实现”。
面向对象: 面向对象的内容包含了面对过程,且较之更抽象和复杂。面向对象不仅是一种编程思维,更是解决问题和处理数据方式的抽象,适用于程序结构设计、数据库系统等多个方面。从较为经典的一句话来形容,那就是:面向对象是一种对现实世界的理解和抽象的方法。现今以面向对象思维为基础发展而来的技术主要有:OOA(Object Oriented Analysis)面向对象的分析,OOD(Object Oriented Design)面向对象的设计,OOP面向对象的编程实现(Object Oriented Programming)。其中面向对象的程序设计实现主要有三要素:封装、继承、多态。OOP以数据为中心,所有的对象都围绕数据来展开,设计数据结构来组织数据,并提供对此类数据所允许的操作。程序中的对象都应该能够接受数据,处理数据并传达数据给其他的对象。所以对象也是OOP中的基本单位,Python更是秉承了一切皆对象的设计理念。根据面向对象的性质能带来以下的好处:
1). 以人更容易理解的方式对复杂的系统进行分析、设计。(封装成类后,只需要关心数据的Input和Output,降低程序框架设计难度,可以快速的搭建系统)
2). 降低编程难度,提高编程效率。(继承、多态,实现了极高的代码重用性)
3). 软件拥有更高的可扩展性。(程序松耦合模块化设计,对单一模块的修改并不会影响到整合系统)
相关概念1
面向对象的一般概念:
⑴对象。
对象是人们要进行研究的任何事物,从最简单的整数到复杂的飞机等均可看作对象,它不仅能表示具体的事物,还能表示抽象的规则、计划或事件。
⑵对象的状态和行为。
对象具有状态,一个对象用数据值来描述它的状态。
对象还有操作,用于改变对象的状态,对象及其操作就是对象的行为。
对象实现了数据和操作的结合,使数据和操作封装于对象的统一体中
⑶类。
具有相同特性(数据元素)和行为(功能)的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象,类实际上就是一种数据类型。
类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。
类具有操作,它是对象的行为的抽象,用操作名和实现该操作的方法来描述。
⑷类的结构。
在客观世界中有若干类,这些类之间有一定的结构关系。通常有两种主要的结构关系,即一般–具体结构关系,整体–部分结构关系。
①一般–具体结构称为分类结构,也可以说是“或”关系,或者是“is a”关系。
②整体–部分结构称为组装结构,它们之间的关系是一种“与”关系,或者是“has a”关系。
⑸消息和方法。
对象之间进行通信的结构叫做消息。在对象的操作中,当一个消息发送给某个对象时,消息包含接收对象去执行某种操作的信息。发送一条消息至少要包括说明接受消息的对象名、发送给该对象的消息名(即对象名、方法名)。一般还要对参数加以说明,参数可以是认识该消息的对象所知道的变量名,或者是所有对象都知道的全局变量名。
类中操作的实现过程叫做方法,一个方法有方法名、返回值、参数、方法体。
面向对象的特征:
⑴对象唯一性。
每个对象都有自身唯一的标识,通过这种标识,可找到相应的对象。在对象的整个生命期中,它的标识都不改变,不同的对象不能有相同的标识。
⑵抽象性。
抽象性是指将具有一致的数据结构(属性)和行为(操作)的对象抽象成类。一个类就是这样一种抽象,它反映了与应用有关的重要性质,而忽略其他一些无关内容。任何类的划分都是主观的,但必须与具体的应用有关。
⑶继承性。
继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容。
继承性是面向对象程序设计语言不同于其它语言的最重要的特点,是其他语言所没有的。
在类层次中,子类只继承一个父类的数据结构和方法,则称为单重继承。
在类层次中,子类继承了多个父类的数据结构和方法,则称为多重继承。
多重继承,JAVA、VB、NET、Objective-C均仅支持单继承,注意在C++多重继承时,需小心二义性。
在软件开发中,类的继承性使所建立的软件具有开放性、可扩充性,这是信息组织与分类的行之有效的方法,它简化了对象、类的创建工作量,增加了代码的可重用性。
采用继承性,提供了类的规范的等级结构。通过类的继承关系,使公共的特性能够共享,提高了软件的重用性。
⑷多态性(多形性)
多态性是指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态性。
多态性允许每个对象以适合自身的方式去响应共同的消息。
多态性增强了软件的灵活性和重用性。
Python的解释器
解析器是程序源代码和计算机硬件之间的软件逻辑层,它将源代码文件翻译成计算机可执行的文件,既Python的交互式运行环境。Python拥有多种使用不同语言实现的解释器。常用的有如:
1). CPython(C):是速度最快也是最常用的官方默认的Python解析器,会将Python解释为字节码(bytecode)
2). Jython(Java):可以将Java模块加载到Python模块中使用,能直接调用java类库。其使用了JIT(Just In Time即时编译)技术,运行Python代码时,会将其转化为Java代码,再交由JRE来处理。并且Jython可以将Python程序做成Jar包,使用Jython让Python程序员可以编写Java程序。
注1:JIT(即时编译技术),会将经JVM翻译的字节码后生成的机器码保存起来,当需要再次使用的时候直接调用保存好的机器码,从而不需要再次执行编译过程。提高解析型语言执行效率,使其更靠近编译型语言。但当前的JIT为了减轻编译负载,只会对经常使用的代码进行编译,如:循环。
注2:Java中的JIT,最早的Java建置方案是由一套转译程式(interpreter),将每个Java指令都转译成对等的微处理器指令,并根据转译后的指令先后次序依序执行,由于一个Java指令可能被转译成十几或数十几个对等的微处理器指令,这种模式执行的速度相当缓慢。 针对这个问题,业界首先开发出JIT(just in time)编译器。当Java执行runtime环境时,每遇到一个新的类别(class:类别是Java程式中的功能群组),类别是Java程式中的功能群组-JIT编译器在此时就会针对这个类别进行编译(compile)作业。经过编译后的程式,被优化成相当精简的原生型指令码(native code),这种程式的执行速度相当快。花费少许的编译时间来节省稍后相当长的执行时间,JIT这种设计的确增加不少效率,但是它并未达到最顶尖的效能,因为某些极少执行到的Java指令在编译时所额外花费的时间可能比转译器在执行时的时间还长,针对这些指令而言,整体花费的时间并没有减少。基于对JIT的经验,业界发展出动态编译器(dynamic compiler),动态编译器仅针对较常被执行的程式码进行编译,其余部分仍使用转译程式来执行。也就是说,动态编译器会研判是否要编译每个类别。动态编译器拥有两项利器:一是转译器,另一则是JIT,它透过智慧机制针对每个类别进行分析,然后决定使用这两种利器的哪一种来达到最佳化的效果。动态编译器针对程式的特性或者是让程式执行几个循环,再根据结果决定是否编译这段程式码。这个决定不见得绝对正确,但从统计数字来看,这个判断的机制正确的机会相当高。事实上,动态编译器会根据「历史资料」做决策,所以程式执行的时间愈长,判断正确的机率就愈高。以整个结果来看,动态编译器产生的程式码执行的速度超越以前的JIT技术,平均速度可提高至50%。2
3). PyPy(Python): 使用Python的自实现,会将Python程序直接转化为机器码,性能比CPython更好。
4). IronPython(C#):能够直接调用.net平台的函数库,也可以将Python程序编译成.net程序。
5). Cython(C/C++):Cyhon将Python代码转化为C/C++代码,相同的也可以在Python代码中直接使用C/C++函数模块。Cython执行Python程序的效率比CPython要更加快,Cython也可以交Python程序编译成一个类库(Linux的.so文件、Win的.dll文件、Python的Module文件都是函数和属性的集合,叫法上有所区别),并可以将这个类库当作一个模块直接使用。Cython的文件扩展名为.pyx。
Python程序设计的思想
Python语言的设计理念是“简单”、“语法严格”、“可读性高”,其中Python独特的缩进格式就是为此而生,严格的缩进语法,可以使代码看起来更加清晰而优雅。而且为了Python程序的可读性和可维护性,以此来支撑大型系统的开发,设计团队提倡“用一种最好的方法,来解决一个问题”的程序实现思路。Python也被称之为“胶水语言”,其提供了丰富的API和不同类型的解释器,使其可以轻松的嵌入多种语言来扩充模块。相对的,Python编译器本身也能够嵌入到其他需要脚本语言的程序内。
Python的编程风格
代码组:缩进相同的一组语句构成的代码块。代码组首行以关键字开始,以:结束,”:”是代码块的起始标识,并且以关键字开始的一个语句的末尾必须有” : “才可以通过语法的检测。在代码组中的同一行若有多个语句则需要使用” ; “隔开。
注释:在Python中,以”’ ‘”三引号来作为注释的标识,可以作为单行注意,亦可以作为多行注释。同时也被用作每一个Python的Mudole文件的文档声明,之后便可以通过Module的.__doc__方法来调用Module文档。
最后
总而言之,要响深入的学习一门语言,需要从理论到实际的双向结合、同步进行,才可以编写出符合该语言风格的程序来。再往后的博文中,我们继续来一起学习Python的程序编写和其理论的底层实现。
Jmilk