@wenshizhang
2016-08-18T16:51:23.000000Z
字数 2734
阅读 426
suse实习
python
要解释为什么把类跟模块放在一起,还要从python语言本身的特点。
计算机是不能够识别高级语言的,所以当我们运行一个高级语言程序的时候,就需要一个“翻译机”来从事把高级语言转变成计算机能读懂的机器语言的过程。这个过程分成两类,第一种是编译,第二种是解释。
编译型语言在程序执行之前,先会通过编译器对程序执行一个编译的过程,把程序转变成机器语言。运行时就不需要翻译,而直接执行就可以了。最典型的例子就是C语言。
解释型语言就没有这个编译的过程,而是在程序运行的时候,通过解释器对程序逐行作出解释,然后直接运行,最典型的例子是Ruby。
通过以上的例子,我们可以来总结一下解释型语言和编译型语言的优缺点,因为编译型语言在程序运行之前就已经对程序做出了“翻译”,所以在运行时就少掉了“翻译”的过程,所以效率比较高。但是我们也不能一概而论,一些解释型语言也可以通过解释器的优化来在对程序做出翻译时对整个程序做出优化,从而在效率上超过编译型语言。
此外,随着Java等基于虚拟机的语言的兴起,我们又不能把语言纯粹地分成解释型和编译型这两种。
用Java来举例,Java首先是通过编译器编译成字节码文件,然后在运行时通过解释器给解释成机器文件。所以我们说Java是一种先编译后解释的语言。
再换成C#,C#首先是通过编译器将C#文件编译成IL文件,然后在通过CLR将IL文件编译成机器文件。所以我们说C#是一门纯编译语言,但是C#是一门需要二次编译的语言。同理也可等效运用到基于.NET平台上的其他语言。
写python程序的时候,有注意到这一点。如果出现了类似于关键字写错的显而易见错误,错误行之前的程序是不会执行的,程序直接报错。解释型语言运行就是解释器解释一句,运行一句。这样就很奇怪,程序一句没有解释,解释器是如何”看见“后面有一个关键字写错了的呢?合理的设想一下,在解释器解释之前,程序肯定是经过了编译阶段。实际上就是这样的,解释器在解释之前,会先把python中的模块编译成.pyc文件,使重用该模块的程序不用再重复相同的工作。
那从这个角度解释模块和类就很清楚,模块就是一个单独的.py最终会编译成.pyc文件的那个文件。程序运行的时候,python解释器会先去寻找有没有.pyc文件,如果没有才会编译一遍。
这里就提出两个新的问题:
* 既然都是.py结尾的,编译器是如何区分哪个才是程序执行的入口的
* 如果修改了模块中的代码,.pyc文件并没有发生改变,解释器怎么保证执行修改后的程序
先来解释第一个问题。这个很简单,python中有一个__name__
的系统变量,用来只是模块应该如何被加载。如果__name__
被设置为__main__
表示这个程序是直接运行的,如果被设置为模块的名称,表示这是一个模块,程序执行的时候会去寻找__main__
。
init方法是类创建实例时候调用的初始化方法,可以初始化一些需要的成员变量。__init__方法的第一个参数一定是self表示这个实例本身,初始化的属性也是这个实例的属性。__init__
方法使实例创建的时候可以传递参数作为成员变量的初始值。实际上,大部分的成员方法定义时候都需要加上self参数,指向该实例本身,而调用时self并不需要传入**
成员方法是和实例绑定的,并且方法可以直接访问实例的数据(属性、变量等等),这些都是普通函数不具备的特性。
__slot__
类的属性或者方法可以在类定义的时候定义,也可以在实例创建以后动态绑定。
#静态定义
class animal:
def run():
print 'Hello, this is animal'
a = animal()
a.run()
#动态绑定
class animal:
pass
def run():
print 'Hello,this is animal'
a = animal()
a.run = MethodType(run,a,animal)
a.run()
这样就很灵活,实例可以为类动态的绑定一个属性或者方法。如果一个类并不想要实例可以动态的绑定属性呢?这时候需要用到slot关键字,它可以限制类的属性
class animal:
__slot__=("type","age")
a = animal()
a.type = 'dog'
a.age = 10
a.name='Bob' #报错,该类没有name属性
@property
使方法变成属性,像属性一样赋值。例如:
class student:
@property
def score(self):
return self.score
@score.setter
def score(self,score):
if not isinstance(score,int):
raise ValueError("score must be an interger!")
if score <0 or score > 100:
raise ValueError('score must between 0-100')
self.score = score
s = student()
s.score = -10
print s.score
@property创建了一个score.setter,这样在设置score属性的时候,可以对数值做一些判断,增强程序健壮性。
如模块基本上就是一个包含了所有你定义的函数和变量的文件。为了在其他程序中重用模块,模块的文件名必须以.py为扩展名。
模块可以从其他程序 输入 以便利用它的功能。这也是我们使用Python标准库的方法。首先,我们将学习如何使用标准库模块。
你可以使用内建的dir函数来列出模块定义的标识符。标识符有函数、类和变量。当你为dir()
提供一个模块名的时候,它返回模块定义的名称列表。如果不提供参数,它返回当前模块中定义的名称列表。
python中没有访问修饰符(简直是为民着想的好语言阿),默认所有的成员变量和成员方法都是公有的。但是再python程序员界中有这样一个公约:如果想要一个变量或者方法是该类自己独有的,定义的时候以_
开头。同理,如果某一个类中有一个_
开头的方法或者变量,则说明原作者的意思是这个属性或者方法是本类独用的,其他的类不可以用。当然这只是一个公约,如果有人就是非要访问也没办法。想要在语法层面对访问做限制,则在方法或者属性名前加__
(双下划线),这样就可以了。这里要注意一点:如某一个方法或者属性命名是以双下划线开头,以双下划线结束,这表示是类的特殊属性(比如:doc、name)或者特殊方法(比如:init),这些并不是private。