引言提到面向对象,总是离不开几个重要的术语:多态(Polymorphism),继承(Inheritance)和封装(Encapsulation)。
Python也是一种支持OOP的动态语言,本文将简单阐述Python 对面向对象的支持。
在讨论Python的OOP之前,先看几个OOP术语的定义:•类:对具有相同数据和方法的一组对象的描述或定义。
•对象:对象是一个类的实例。
•实例(instance):一个对象的实例化实现。
•标识(identity):每个对象的实例都需要一个可以唯一标识这个实例的标记。
•实例属性(instance attribute):一个对象就是一组属性的集合。
•实例方法(instance method):所有存取或者更新对象某个实例一条或者多条属性的函数的集合。
•类属性(classattribute):属于一个类中所有对象的属性,不会只在某个实例上发生变化•类方法(classmethod):那些无须特定的对性实例就能够工作的从属于类的函数。
1.Python中的类与对象Python中定义类的方式比较简单:class类名:类变量def __init__(self,paramers):def函数(self,...)其中直接定义在类体中的变量叫类变量,而在类的方法中定义的变量叫实例变量。
类的属性包括成员变量和方法,其中方法的定义和普通函数的定义非常类似,但方法必须以self作为第一个参数。
举例:class MyFirstTestClass:classSpec="it is a test class"def __init__(self,word):print "say "+worddef hello(self,name):print "hello "+name在Python类中定义的方法通常有三种:实例方法,类方法以及静态方法。
这三者之间的区别是实例方法一般都以self作为第一个参数,必须和具体的对象实例进行绑定才能访问,而类方法以cls作为第一个参数,cls表示类本身,定义时使用@classmethod;而静态方法不需要默认的任何参数,跟一般的普通函数类似.定义的时候使用@staticmethod。
class MethodTest():count= 0def addCount(self):MethodTest.count+=1print "I am an instance method,my count is" + str(MethodTest.count), self@staticmethoddefstaticMethodAdd():MethodTest.count+=1print"I am a static methond,my count is"+str(MethodTest.count)@classmethoddefclassMethodAdd(cls):MethodTest.count+=1print"I am a class method,my count is"+str(MethodTest.count),clsa=MethodTest()a.addCount()'''I am an instance method,my count is 1 <__main__.MethodTest instanceat 0x011EC990>'''a.staticMethodAdd() ;#I am a static methond,my count is2MethodTest.staticMethodAdd() ;#I am a static methond,my count is3a.classMethodAdd() ;#I am a class method,my count is4 __main__.MethodTestMethodTest.classMethodAdd() ;#I am a class method,my count is5 __main__.MethodTest MethodTest.addCount()'''Traceback(most recent call last):File"<pyshell#5>", line 1, in <module>MethodTest.addCount()TypeError:unbound method addCount() must be called with MethodTest instance asfirst argument (got nothing instead)'''从上面的例子来看,静态方法和类方法基本上区别不大,特别是有Java编程基础的人会简单的认为静态方法和类方法就是一回事,可是在Python中事实是这样的吗?看下面的例子:MethodTest.classMethodAdd() ;#I am a class method,my count is5 __main__.MethodTestclass subMethodTest(MethodTest):passb=subMethodTest()b.staticMethodAdd() ;#I am a static methond,my count is6b.classMethodAdd() ;#I am a class method,my count is7 __main__.subMethodTesta.classMethodAdd() ;#Iam a class method,my count is8 __main__.MethodTest如果父类中定义有静态方法a(),在子类中没有覆盖该方法的话,Sub.a()仍然指的是父类的a()方法。
而如果a()是类方法的情况下,Sub.a()指向的是子类。
@staticmethod只适用于不想定义全局函数的情况。
看看两者的具体定义:@staticmethod function is nothing morethan a function defined inside a class. It is callable withoutinstantiating the class first. It’s definition is immutable viainheritance.@classmethod function also callablewithout instantiating the class, but its definition follows Subclass, not Parent class, via inheritance. That’s because the firstargument for @classmethod function must always be cls (class).•封装和访问控制与Java不同,Python的访问控制相对简单,没有public,private,protected等属性,python认为用户在访问对象的属性的时候是明确自己在做什么的,因此认为私有数据不是必须的,但是如果你必须实现数据隐藏,也是可以的,具体方法就是在变量名前加双下划线。
如__privatedata=0,定义私有方法则是在方法名称前加上__下划线。
但即使对于隐藏的数据,也是有一定的方法可以访问的。
方法就是__className__attrName。
Python对于私有变量会进行Namemangling是Python中为了方便定义私有的变量和方法,防止和继承类以及其他外部的变量或者方法冲突而采取的一种机制。
在python中通过__spam定义的私有变量为最终被翻译成_classname__spam,其中classname为类名,当类名是以_开头的时候则不会发生Namemangling。
Namemangling 存在的一个问题是当字符串长度超过255的时候则会发生截断。
class PrivateTest:__myownedata=12def __myownmethod(self):print"can you see me?"def sayhi(self):print"say hi"class subPrivateTest(PrivateTest):passsubPrivateTest.__myownedataTraceback(most recent call last):File"<pyshell#5>", line 1, in <module>subPrivateTest.__myownedataAttributeError:class subPrivateTest has no attribute '__myownedata'subPrivateTest._PrivateTest__myownedata•构造函数和析构函数Python的构造函数有两种,__init__和__new__,__init__的调用不会返回任何值,在继承关系中,为了保证父类实例正确的初始化,最好显示的调用父类的__init__方法。
与__init__不同,__new__实际是个类方法,以cls作为第一个参数。
如果类中同时定义了__init__和__new__方法,则在创建对象的时候会优先使用__new__. class A(object):def __init__(self):print("in init")def __new__(self):print("in new")A()如果__new__需要返回对象,则会默认调用__init__方法。
利用new创建一个类的对象的最常用的方法为:super(currentclass,cls).__new__(cls[, ...])class A(object):def __new__(cls):Object = super(A,cls).__new__(cls)print "in New"return Objectdef __init__(self):print "in init"class B(A):def __init__(self):print "in B's init"B()__new__构造函数会可变类的定制的时候非常有用,后面的小节中会体现。