面向对象有三大特征:多态(对应方法覆写)、封装、继承(对应方法重载),这个在Java中已经说得很详细了,这里面只是介绍Python在这三个特性方面的实现。
1 创建自定义类
Python和Java一样使用class关键字来创建对象。语法格式如下:
class 类名: def 方法名1(参数列表): pass
从上述语法来看,类必须使用class关键字来定义,接着是类名,然后使用pass占位。
一个例子如下:
class Person: def getName(self): print 'My name is AIQI' def getAge(self): print 'My age is 27' def getHoppy(self): print 'My hobby is love you' >>> import Person >>> person = Person.Person() >>> person.getName() My name is AIQI >>> person.getAge() My age is 27 >>> person.getHoppy() My hobby is love you
实例应用
myStr = raw_input('Please input one object:') class MyWorld: #define one person method def printPerson(self): self.myTalk = 'I can speak' self.myLimbs = 'I can move' print 'I am a person so,I can %s, %s' % (self.myTalk, self.myLimbs) #define one pig method def printPig(self): self.myTalk = 'Hengheng...' self.myWeight = 'I am fat' print 'I am a pig so,%s, %s' % (self.myTalk, self.myWeight) if __name__ == '__main__': myWorld = MyWorld() if myStr == 'Person': myWorld.printPerson() elif myStr == 'Pig': myWorld.printPig() else: print 'No this object'
运行结果:
Please input one object:Person
I am a person so,I can I can speak, I can move
2 属性和方法
类是忧属性和方法组成的,属性是对数据的封装,方法是对行为的描述。在Java中,属性和方法都有访问权限控制符,在python中没有这样的封装级别控制符,在Python中,构造函数、析构函数、私有属性方法、公有属性方法都是通过名称的约定来辨别的。如果函数、方法或者属性的名称以两个下划线开始,则说明为私有类型。相反,如果没有以两个下划线开始,则表示为公有属性。在Java中还有一个受保护的类型修饰符protected 在python中不存在这种类型。
在python中也有静态属性和实例属性。实例属性即以self作为前缀的属性,如果在类的方法中定义的变量没有使用self作为前缀声明,那么该变量就是一个普通的局部变量。
2.1 类属性
class Fly: #define one class attribute price = 23 def __init__(self): self.direction = 'To Paris' speed = 32 if __name__ == '__main__': print Fly.price fly = Fly() print fly.direction Fly.price = fly.price + 10 print 'fly,fly away' print 'the price increase:' + str(fly.price) myFly = Fly() print myFly.price 输出结果: 23 To Paris fly,fly away the price increase:33 33
另外方法中的局部变量speed是不能被实例及类来引用的
2.2 私有属性
将公有的实例属性direction修改成私有__direction
class Fly: #define one class attribute price = 23 def __init__(self): self.__direction = 'To Paris' self.speed = 32 if __name__ == '__main__': print Fly.price fly = Fly() print fly.__direction Fly.price = fly.price + 10 print 'fly,fly away' print 'the price increase:' + str(fly.price) myFly = Fly() print myFly.price 输出结果: 23 Traceback (most recent call last): File "Fly.py", line 10, in <module> print fly.__direction AttributeError: Fly instance has no attribute '__direction'
显然报错了,也就是私有的属性不能被实例化对象访问。Python提供了直接访问私有属性的方式
实例化对象名._类名__私有属性名
class Fly: #define one class attribute price = 23 def __init__(self): self.__direction = 'To Paris' self.speed = 32 if __name__ == '__main__': print Fly.price fly = Fly() print fly._Fly__direction Fly.price = fly.price + 10 print 'fly,fly away' print 'the price increase:' + str(fly.price) 输出结果: 23 To Paris fly,fly away the price increase:33
2.3 数据属性
数据属性不需要预先定义,当数据属性初次被使用时,即被创建并赋值。
class DataAttribute: pass if __name__ == '__main__': data = DataAttribute() data.name = 'I am not defined' print data.name 输出结果:I am not defined
2.4 内置属性
前面已经提到的__doc__就是内置属性。
class FatherClass: def __init__(self): self.built = 'I am the method __init__ \'s attribute' class SonClass(FatherClass): def accept(self): self.acceptAttribute = "I am the attribute of SonClass's method accept" if __name__ == '__main__': f = FatherClass() s = SonClass() print "Inherite attribute from father class:", s.built print "the tuple formed by base class:", SonClass.__bases__ print "the dict formed by neizhi:", s.__dict__ print s.__module__ print s.__doc__ print SonClass.__name__ 输出结果: Inherite attribute from father class: I am the method __init__ 's attribute the tuple formed by base class: (<class __main__.FatherClass at 0x7f8d92e4ea10>,) the dict formed by neizhi: {'built': "I am the method __init__ 's attribute"} __main__ None SonClass
说明:上面代码中,使用内置属性__bases__来输出其父类组成的元组。__dict__属性用例输出子类实例属性组成的字典,__module__属性用来输出当前运行的模块名称,__doc__属性用来输出doc文档,而__name__属性用例输出当前对象的类名。
2.5 类的方法
类似属性,方法也有类方法和实例方法,定义规则相同,在Java中用static来定义,而python中没有static关键字,而是使用函数staticmethod()或者@staticmethod指令的方式来定义静态方法。
2.5.1 类方法
class Methods: @staticmethod def myMethod(): print 'This is a static method' def __myMethod(): print 'This is a private method' def getMyMethod(): print 'I willbe converted to static method' conversion = staticmethod(getMyMethod) conPrivate = staticmethod(__myMethod) if __name__ == '__main__': methods = Methods() methods.myMethod() Methods.myMethod() #访问转换为静态方法后的原有方法 methods.conversion() Methods.conversion() methods.conPrivate() Methods.conPrivate() 输出结果: This is a static method This is a static method I willbe converted to static method I willbe converted to static method This is a private method This is a private method
上面代码中,在类Methods中分别声明了一个静态方法myMethod,一个私有方法__myMethod和一个普通方法getMyMethod,然后用函数staticmethod()将普通方法getMyMethod转换为静态方法conversion,将私有方法__myMethod转换为静态方法conPrivate
2.5.2 内置方法
有许多类内置的方法,这些方法可能会被封装起来被别的函数调用。
下面介绍几个重要的__init__方法
1.__init__方法
这个方法在Python中是构造函数,与Java不同的是,Java中的构造函数和类名是一样的,Python中不必如此,实际上构造函数更严谨的说法是初始化函数,所以__init__还是可以的。
class People: def __init__(self, name): self.name = name def sayHi(self): print 'Hello, My name is:', self.name p = People('AiQi') p.sayHi() 输出结果:Hello, My name is: AiQi
2.__del__方法
__del__方法的主要作用是释放被占用的资源,在Python中是析构函数。
所谓析构函数是:析构函数(destructor) 与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。
class Room: count = 0 def __init__(self, name): self.name = name print 'Initing, name is %s' % self.name Room.count += 1 def __del__(self): print '%s say byebye:' % self.name Room.count -= 1 if Room.count == 0: print 'I am the last one' else: print 'There is %d persons left' % Room.count def sayHi(self): print 'Hello,My name is %s ' % self.name def howMany(self): if Room.count == 1: print 'I am the last one' else: print 'There is %d persons left' % Room.count if __name__ == '__main__': room = Room('AiQi') room.sayHi() 运行结果: Initing, name is AiQi Hello,My name is AiQi I am the last one Initing, name is Ren Hello,My name is Ren There is 2 persons left AiQi say byebye: There is 1 persons left Ren say byebye: Exception AttributeError: "'NoneType' object has no attribute 'count'" in <bound method Room.__del__ of <__main__.Room instance at 0x7fc513263200>> ignored AiQi say byebye: Exception AttributeError: "'NoneType' object has no attribute 'count'" in <bound method Room.__del__ of <__main__.Room instance at 0x7fc5132631b8>> ignored
3. __new__方法
__new__方法在创建对象时被调用,返回当前对象的一个实例。看起来和__init__方法没有什么区别。实际上,__init__方法在创建完对象之后才被调用,对当前对象的实例进行初始化,而__new__方法则是在创建对象时被调用的。
class MyNew: def __init__(self): print ("__init__") def __new__(self): print ("__new__") if __name__ == '__main__': myNew = MyNew()
4.__setitem__方法
_setitem__专用方法的含义是进行赋值时,创建字典对象
class MySetitem: def __setitem__(self, key, value): print 'key=%s, value=%s' % (key, value) mySetitem = MySetitem() mySetitem['a'] = 'Alice' mySetitem['b'] = 'Quinta' mySetitem['c'] = 'Amy' 执行结果: key=a, value=Alice key=b, value=Quinta key=c, value=Amy
5.__getitem__方法
__getitem__用于返回字典的值。这两个方法和java的setter和getter方法是类似的。
6.__delitem__方法
__delitem__方法是在调用"del 实例对象[key]"语句时调用。
class MyDelitem: def __delitem__(self, key): print 'delete item:%s' % key myDelitem = MyDelitem() del myDelitem['dcy'] 输出结果:delete item:dcy
7.__cmp__方法
这个内置方法被封装用于给==比较累实例时候进行调用。
class MyCmp: def __cmp__(self, other): print '__cmp__ is called' return 0 if __name__ == '__main__': mycmp1 = MyCmp() mycmp2 = MyCmp() print mycmp1 == mycmp2 输出: __cmp__ is called True
2.6 方法的动态特性
python语言是一种完全面向对象的动态语言,主要体现在:可以动态添加类的方法,将某个已经定义的方法添加到类中。如果类本身已经有了同名的方法,那么将会替换掉类中的方法体。
class_name.method_name = exist_name class Yesterday: pass def today(self): print 'Today is a nice day' if __name__ == '__main__': Yesterday.yesterday = today yes = Yesterday() yes.yesterday() 输出结果:Today is a nice day
3 继承
继承是子类继承父类的属性和方法,python中没有extends关键字,用括号
class class_name(father_class_name)
一个例子:
3.1 super调用父类方法
python支持用super关键字来调用父类的方法
''' Created on 2013-8-6 @author: Landau ''' class Father: def __init__(self): print 'I am the __init__ of father' print 'Use later' class Son(Father): def __init__(self): print 'I am the __init__ of son' Father.__init__(self) b = Son()
我们也可以使用super关键字来实现上面的功能
3.2 多继承
python允许多重继承。语法格式如下:
class class_name(fatherclass1_name,fatherclass2_name)
多继承是这样的,比如一个人,眼睛像妈妈,肤色像爸爸。这就是多继承。
3.3 类的命名空间
类和类成员的名称是丰富的,为了描述一个具体的对象,需要对类和类成员进行设计,在设计类和类成员过程中,难免会出现类的名称或类成员中的方法相同的情况,这样就会造成代码混乱,从而使代码的可读性降低。使用命名空间可以解决此问题。
在java中,我们只要把类放到各自的包中,就可以避免类的名称或者类成员重复了,我们可以认为package是java的命名空间。
在python中,定义类时,所有位于class语句中的代码都在特殊的命名空间中执行,该命名空间被称为类命名空间(class namespace)。这个类命名空间不仅可以被类中所有成员访问,还可以被类的实例方法访问。
3.4 继承检查
python提供了内建的issubclass函数用于继承检查
issubclass函数的第一个参数是子类,第二个参数是可能的父类,类似还有一个函数isinstance,用于检查一个对象是不是一个类的实例,第一个参数是对象,第二个参数是可能的类。
3.5 新式类
新式类是指从python2.2开始引入的类。通常情况下,从object或者其他内置类型衍生的类,都被称为新式类。
__slots__类属性
这个类属性用于替代__dict__属性
__slots__是一个类变量,可以由一系列对象组成,使用所有合法标识构成的实例属性的集合来表示。它也可以是一个列表、元组或可迭代对象,总之,任何试图创建一个其名不在__slots__中的实例属性的操作都将引发AttributeError异常,而且实例属性必须初始化。
一般情况下,__slots__类属性在class语句顶层设置。下面通过一个例子说明:
class MyLimiter(object): __slots__ = 'my_name', 'my_age', 'my_hobby' if __name__ == '__main__': x = MyLimiter() x.my_name = 'AiQi' print x.my_name