Python程序设计6——面向对象
面向对象有三大特征:多态(对应方法覆写)、封装、继承(对应方法重载),这个在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
最新文章
- [Python核心编程] 第1章 欢迎来到Python世界
- jmeter(二)录制脚本
- ajax文件下载
- 关于如何来构造一个String类
- Linux字符设备
- JS高级程序设计2nd部分知识要点1
- Unity3D MainCamera和NGUI UICamera的小插曲
- Android Bitmap 全面解析(四)图片处理效果对比 ...
- 【Android 界面效果21】Android ViewPager使用详解
- VS2013 调试卡顿
- overlay
- 第1阶段——关于u-boot目标文件start.o中.globl 和.balignl理解(3)
- jumpserver 堡垒机环境搭建(图文具体解释)
- [Swift]动态变化顶部状态栏(statusBar)的颜色
- VB.NET或C#报错:You must hava a license to use this ActiveX control.
- MyBatis注解-动态SQL 一个 SqlProvider的demo
- BZOJ4077 : [Wf2014]Messenger
- pycharm的小问题之光标
- 【题解】Luogu CF343D Water Tree
- Laravel 更新数据时在表单请求验证中排除自己,检查指定字段唯一性